📜  树形数据结构简介

📅  最后修改于: 2022-05-13 01:57:16.870000             🧑  作者: Mango

树形数据结构简介

数据结构是一种在计算机中组织和存储数据以便更有效地使用的专门方法。有各种类型的数据结构,如堆栈、链表和队列,按顺序排列。例如,链接数据结构由一组节点组成,这些节点通过链接或点链接在一起。

类似地,树数据结构是一种以树状结构排列的层次数据。它由中心节点、结构节点和子节点组成,它们通过边连接。我们也可以说树数据结构具有相互连接的根、分支和叶子。

树是非线性的,并且是由节点集合组成的分层数据结构,因此树的每个节点都存储一个值,即对节点的引用列表(“子节点”)。

递归定义:一棵树由一个根和零个或多个子树 T 1 、T 2 、...、T k组成,使得从树的根到每个子树的根都有一条边。

树形数据结构中的基本术语:

  • 父节点:作为节点的前驱节点的节点称为该节点的父节点。 { 2}是 { 6, 7}的父节点。
  • 子节点:作为节点的直接后继的节点称为该节点的子节点。示例: { 6, 7}是 { 2}的子节点。
  • 根节点:树的最顶层节点或没有任何父节点的节点称为根节点。 { 1}是树的根节点。一棵非空树必须恰好包含一个根节点和从根到树的所有其他节点的路径。
  • 节点的度数:连接到该节点的子树的总数称为节点的度数。叶节点的度数必须为0 。树的度是树中所有节点中节点的最大度。节点 { 3}的度数是3
  • 叶节点或外部节点:没有任何子节点的节点称为叶节点。 { 6, 14, 8, 9, 15, 16, 4, 11, 12, 17, 18, 19}是树的叶子节点。
  • 节点的祖先:根到该节点的路径上的任何前驱节点都称为该节点的祖先。 { 1, 2}是节点 { 7}的父节点
  • 后代:从叶节点到该节点的路径上的任何后继节点。 { 7, 14}是节点的后代。 { 2}
  • Sibling:同一个父节点的子节点称为兄弟节点。 { 8, 9, 10}称为兄弟姐妹。
  • 节点深度:从根到节点的边数。节点 { 14}的深度为3
  • 节点的高度:从该节点到叶子的最长路径上的边数。节点 { 3}的高度为2
  • 的高度:树的高度是根节点的高度,即从根到最深节点的边数。上述树的高度是3
  • 节点级别:从根节点到该节点的路径上的边数。根节点的级别为 0
  • 内部节点:至少有一个孩子的节点称为内部节点。
  • 节点的邻居:该节点的父节点或子节点称为该节点的邻居。
  • :树的任何节点及其后代

让我们考虑另一个树数据结构的例子。

这里,

节点 A 是根节点

B 是 D 和 E 的父级

D和E是兄弟姐妹

D、E 和 F 是叶节点

A和B是E的祖先

关于树数据结构的几个例子:下面描述了演示上述几个术语的代码:


C++
// C++ program to demonstrate some of the above
// terminologies
#include 
using namespace std;
// Function to add an edge between vertices x and y
void addEdge(int x, int y, vector >& adj)
{
    adj[x].push_back(y);
    adj[y].push_back(x);
}
// Function to print the parent of each node
void printParents(int node, vector >& adj,
                  int parent)
{
    // current node is Root, thus, has no parent
    if (parent == 0)
        cout << node << "->Root" << endl;
    else
        cout << node << "->" << parent << endl;
    // Using DFS
    for (auto cur : adj[node])
        if (cur != parent)
            printParents(cur, adj, node);
}
// Function to print the children of each node
void printChildren(int Root, vector >& adj)
{
    // Queue for the BFS
    queue q;
    // pushing the root
    q.push(Root);
    // visit array to keep track of nodes that have been
    // visited
    int vis[adj.size()] = { 0 };
    // BFS
    while (!q.empty()) {
        int node = q.front();
        q.pop();
        vis[node] = 1;
        cout << node << "-> ";
        for (auto cur : adj[node])
            if (vis[cur] == 0) {
                cout << cur << " ";
                q.push(cur);
            }
        cout << endl;
    }
}
// Function to print the leaf nodes
void printLeafNodes(int Root, vector >& adj)
{
    // Leaf nodes have only one edge and are not the root
    for (int i = 1; i < adj.size(); i++)
        if (adj[i].size() == 1 && i != Root)
            cout << i << " ";
    cout << endl;
}
// Function to print the degrees of each node
void printDegrees(int Root, vector >& adj)
{
    for (int i = 1; i < adj.size(); i++) {
        cout << i << ": ";
        // Root has no parent, thus, its degree is equal to
        // the edges it is connected to
        if (i == Root)
            cout << adj[i].size() << endl;
        else
            cout << adj[i].size() - 1 << endl;
    }
}
// Driver code
int main()
{
    // Number of nodes
    int N = 7, Root = 1;
    // Adjacency list to store the tree
    vector > adj(N + 1, vector());
    // Creating the tree
    addEdge(1, 2, adj);
    addEdge(1, 3, adj);
    addEdge(1, 4, adj);
    addEdge(2, 5, adj);
    addEdge(2, 6, adj);
    addEdge(4, 7, adj);
    // Printing the parents of each node
    cout << "The parents of each node are:" << endl;
    printParents(Root, adj, 0);
 
    // Printing the children of each node
    cout << "The children of each node are:" << endl;
    printChildren(Root, adj);
 
    // Printing the leaf nodes in the tree
    cout << "The leaf nodes of the tree are:" << endl;
    printLeafNodes(Root, adj);
 
    // Printing the degrees of each node
    cout << "The degrees of each node are:" << endl;
    printDegrees(Root, adj);
 
    return 0;
}


Java
// java code for above approach
import java.io.*;
import java.util.*;
 
class GFG
{
 
  // Function to print the parent of each node
  public static void
    printParents(int node, Vector > adj,
                 int parent)
  {
 
    // current node is Root, thus, has no parent
    if (parent == 0)
      System.out.println(node + "->Root");
    else
      System.out.println(node + "->" + parent);
 
    // Using DFS
    for (int i = 0; i < adj.get(node).size(); i++)
      if (adj.get(node).get(i) != parent)
        printParents(adj.get(node).get(i), adj,
                     node);
  }
 
  // Function to print the children of each node
  public static void
    printChildren(int Root, Vector > adj)
  {
 
    // Queue for the BFS
    Queue q = new LinkedList<>();
 
    // pushing the root
    q.add(Root);
 
    // visit array to keep track of nodes that have been
    // visited
    int vis[] = new int[adj.size()];
 
    Arrays.fill(vis, 0);
 
    // BFS
    while (q.size() != 0) {
      int node = q.peek();
      q.remove();
      vis[node] = 1;
      System.out.print(node + "-> ");
 
      for (int i = 0; i < adj.get(node).size(); i++) {
        if (vis[adj.get(node).get(i)] == 0) {
          System.out.print(adj.get(node).get(i)
                           + " ");
          q.add(adj.get(node).get(i));
        }
      }
      System.out.println();
    }
  }
 
  // Function to print the leaf nodes
  public static void
    printLeafNodes(int Root, Vector > adj)
  {
 
    // Leaf nodes have only one edge and are not the
    // root
    for (int i = 1; i < adj.size(); i++)
      if (adj.get(i).size() == 1 && i != Root)
        System.out.print(i + " ");
 
    System.out.println();
  }
 
  // Function to print the degrees of each node
  public static void
    printDegrees(int Root, Vector > adj)
  {
    for (int i = 1; i < adj.size(); i++) {
      System.out.print(i + ": ");
 
      // Root has no parent, thus, its degree is
      // equal to the edges it is connected to
      if (i == Root)
        System.out.println(adj.get(i).size());
      else
        System.out.println(adj.get(i).size() - 1);
    }
  }
 
  // Driver code
  public static void main(String[] args)
  {
 
    // Number of nodes
    int N = 7, Root = 1;
 
    // Adjacency list to store the tree
    Vector > adj
      = new Vector >();
    for (int i = 0; i < N + 1; i++) {
      adj.add(new Vector());
    }
 
    // Creating the tree
    adj.get(1).add(2);
    adj.get(2).add(1);
 
    adj.get(1).add(3);
    adj.get(3).add(1);
 
    adj.get(1).add(4);
    adj.get(4).add(1);
 
    adj.get(2).add(5);
    adj.get(5).add(2);
 
    adj.get(2).add(6);
    adj.get(6).add(2);
 
    adj.get(4).add(7);
    adj.get(7).add(4);
 
    // Printing the parents of each node
    System.out.println("The parents of each node are:");
    printParents(Root, adj, 0);
 
    // Printing the children of each node
    System.out.println(
      "The children of each node are:");
    printChildren(Root, adj);
 
    // Printing the leaf nodes in the tree
    System.out.println(
      "The leaf nodes of the tree are:");
    printLeafNodes(Root, adj);
 
    // Printing the degrees of each node
    System.out.println("The degrees of each node are:");
    printDegrees(Root, adj);
  }
}
 
// This code is contributed by rj13to.


Python3
# python program to demonstrate some of the above
# terminologies
 
# Function to add an edge between vertices x and y
 
# Function to print the parent of each node
def printParents(node, adj, parent):
 
    # current node is Root, thus, has no parent
    if (parent == 0):
        print(node, "->Root")
    else:
        print(node, "->", parent)
         
    # Using DFS
    for cur in adj[node]:
        if (cur != parent):
            printParents(cur, adj, node)
 
# Function to print the children of each node
def printChildren(Root, adj):
 
    # Queue for the BFS
    q = []
     
    # pushing the root
    q.append(Root)
     
    # visit array to keep track of nodes that have been
    # visited
    vis = [0]*len(adj)
     
    # BFS
    while (len(q) > 0):
        node = q[0]
        q.pop(0)
        vis[node] = 1
        print(node, "-> ", end=" ")
 
        for cur in adj[node]:
            if (vis[cur] == 0):
                print(cur, " ", end=" ")
                q.append(cur)
        print("\n")
 
# Function to print the leaf nodes
def printLeafNodes(Root, adj):
 
    # Leaf nodes have only one edge and are not the root
    for i in range(0, len(adj)):
        if (len(adj[i]) == 1 and i != Root):
            print(i, end=" ")
    print("\n")
 
# Function to print the degrees of each node
def printDegrees(Root, adj):
 
    for i in range(1, len(adj)):
        print(i, ": ", end=" ")
         
        # Root has no parent, thus, its degree is equal to
        # the edges it is connected to
        if (i == Root):
            print(len(adj[i]))
        else:
            print(len(adj[i])-1)
 
# Driver code
 
# Number of nodes
N = 7
Root = 1
 
# Adjacency list to store the tree
adj = []
for i in range(0, N+1):
    adj.append([])
     
# Creating the tree
adj[1].append(2)
adj[2].append(1)
 
adj[1].append(3)
adj[3].append(1)
 
adj[1].append(4)
adj[4].append(1)
 
adj[2].append(5)
adj[5].append(2)
 
adj[2].append(6)
adj[6].append(2)
 
adj[4].append(7)
adj[7].append(4)
 
# Printing the parents of each node
print("The parents of each node are:")
printParents(Root, adj, 0)
 
# Printing the children of each node
print("The children of each node are:")
printChildren(Root, adj)
 
# Printing the leaf nodes in the tree
print("The leaf nodes of the tree are:")
printLeafNodes(Root, adj)
 
# Printing the degrees of each node
print("The degrees of each node are:")
printDegrees(Root, adj)
 
# This code is contributed by rj13to.



输出
The parents of each node are:
1->Root
2->1
5->2
6->2
3->1
4->1
7->4
The children of each node are:
1-> 2 3 4 
2-> 5 6 
3-> 
4-> 7 
5-> 
6-> 
7-> 
The leaf nodes of the tree are:
3 5 6 7 
The degrees of each node are:
1: 3
2: 2
3: 0
4: 1
5: 0
6: 0
7: 0

树数据结构的类型

不同类型的树数据结构如下:

1.一般树

一般的树数据结构对节点的数量没有限制。这意味着一个父节点可以有任意数量的子节点。

2.二叉树

二叉树的一个节点最多可以有两个子节点。在给定的树形图中,节点 B、D 和 F 是左孩子,而 E、C 和 G 是右孩子。

3.平衡树

如果左子树和右子树的高度相等或最多相差1,则该树称为平衡树数据结构。

4.二叉搜索树

顾名思义,二叉搜索树用于各种搜索和排序算法。示例包括 AVL 树和红黑树。它是一种非线性数据结构。它表明左节点的值小于其父节点,而右节点的值大于其父节点。

特性

以下是树数据结构的属性。

• 对于n 个节点,树的边等于(n – 1)。例如,5 个节点在树数据结构中包含 (5 – 1) 4 条边,如上图所示。

• 结构中的箭头代表路径。每条边连接两个节点。

• 树形图的任意两个节点或顶点恰好由一条边连接。

• 节点的深度定义为从根节点到节点a 的路径长度。节点“a”的高度是从节点“a”到给定树的叶节点的最长路径。

应用

树数据结构的应用如下:

生成树

它是路由器中用于将数据包定向到目的地的最短路径树。

二叉搜索树

它是一种树数据结构,有助于维护排序的数据流。

存储分层数据

树数据结构用于存储分层数据,即按顺序排列的数据。

语法树

语法树表示程序源代码的结构,用于编译器。

特里

它是动态拼写检查的快速有效的方法。它还用于从集合中定位特定键。

它也是一种树形数据结构,可以用数组的形式表示。它用于实现优先级队列。