日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【数据结构-树】1.树与森林(树的遍历、树的存储方法、并查集的实现)

發布時間:2025/3/20 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【数据结构-树】1.树与森林(树的遍历、树的存储方法、并查集的实现) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

樹的定義

是一種數據結構,它是由 n(n>=1)n(n>=1)n(n>=1) 個有限結點組成一個具有層次關系的集合。把它叫做 “樹” 是因為它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。它具有以下的特點

  • 每個結點有零個或多個子結點;
  • 沒有父結點的結點稱為根結點;
  • 每一個非根結點有且只有一個父結點;
  • 除了根結點外,每個子結點可以分為多個不相交的子樹;
  • 樹適合于表示具有層次的數據。樹中的某個結點(除了根結點)最多只和上一層的一個結點(及其父結點)有直接關系,根結點沒有直接上層結點,因此在n個結點的樹中有n-1條邊。

    而樹中每個結點與其下一層的零個或多個結點(及其子女結點)有直接關系。

    基本術語

    以下概念不要求去記,理解概念即可,腦中要有圖

    祖先結點:根結點10到結點3的唯一路徑上的任意結點,如結點10是結點3的祖先結點

    子孫結點:如結點3是結點10的子孫結點

    雙親結點:路徑上最靠近結點3的結點,如5是3的雙親結點(注意,根結點是沒有雙親結點的,如結點10)

    孩子結點:如結點3是結點5的孩子結點

    兄弟結點:有相同雙親的結點,如結點3和結點7有共同的雙親結點5,所以結點3和結點7是兄弟結點

    結點的度:樹中一個結點的子結點個數

    樹的度:樹中結點最大度數

    分支結點:度大于0的結點

    葉子結點:度為0的結點

    結點的層次:從樹根開始定義,根節點為第1層,它的子結點為第2層,以此類推

    結點的深度:從根結點開始自頂向下逐層累積的

    結點的高度:從也結點開始自底向上逐層累積的

    樹的高度:樹中結點的最大層數

    有序樹:樹中結點的字數從左到右是有次序的,不能交換

    無序樹:不是有序樹,就是無序樹

    路徑:樹中兩個結點之間的所經過的結點序列構成的

    路徑長度:路徑上所經過邊的個數

    森林:由m(m≥0)m(m≥0)m(m0) 棵互不相交的樹的集合。(樹把根結點去掉就變成了森林,給n棵獨立的樹加上一個結點,并把這n棵樹變成該結點的子樹,則森林變成了樹)

    樹的性質

    樹有這么幾最基本的性質

  • 樹中的結點數等于所有節點數的度數+1(這個1是根結點)
  • 度為m的樹中第i層,最多有mi?1m^{i-1}mi?1 個結點($ i ≥ 1 $)
  • 高度為h的m叉樹至多有(mh?1)(m?1)\frac{(m^h-1)}{(m-1)}(m?1)(mh?1)? 個結點
  • 具有n個結點的m叉樹的最小高度為 $log_m(n(m-1)+1)(向上取整) $
  • 樹的存儲結構

    樹的存儲方式有很多種,既可以采用順序存儲,也可以采用連式存儲。下面介紹3中常用的存儲結構。下圖為使用的示例樹形結構。



    1. 雙親表示法

    這種存儲方式采用一組連續空間來存儲每個結點,同時在每個結點中增設一個偽指針,指示其雙親結點在數組中的位置。

    pos0123456789
    parent-1000113666
    dataRABCDEFGHK

    解釋:R是根結點,沒有雙親結點,所以parent為-1;A,B,C是結點R的子節點,所以A,B,C的parent均為R的位置,也就是0;D,E是結點A的子節點,所以D,E的parent均為A的位置,也就是1;B沒有子結點;F是結點C的子節點,所以F的parent為C的位置,也就是3;G,H,K是結點F的子節點,所以G,H,K的parent均為F的位置,也就是6

    其存儲結構可以是

    struct TreeNode{int pos;char value;int parent;TreeNode *next; }

    這種存儲結構的優點 :很快找到每個結點的雙親結點

    缺點 :如果要求結點的孩子時,需要遍歷整個結構

    2. 孩子表示法

    孩子表示法是將每個結點的孩子結點都用單鏈表接起來,形成一個線性結構,此時n個結點就有n個孩子鏈表

    posvaluechild’pos1child’pos2child’pos3so on
    0R123-
    1A45-
    2B-
    3C6-
    4D-
    5E-
    6F789-
    7G-
    8H-
    9K-

    解釋:A,B,C是結點R的子節點,所以結點R子節點的位置為1,2,3;D,E是結點A的子節點,結點A的子結點位置為4,5;B沒有子結點;F是結點C的子節點,C的子結點位置為6;G,H,K是結點F的子節點,F的子結點位置是7,8,9

    其存儲結構可以是

    struct TreeNode{int pos;char value;vector<int> child;TreeNode *next; }

    這種存儲結構的優點 :很快找到每個結點的結點

    缺點 :如果要求結點的雙親時,需要遍歷整個結構

    3. 孩子兄弟表示法

    孩子兄弟表示法又稱二叉樹表示法,即以二叉鏈表作為樹的存儲結構。

    孩子兄弟表示法是每個結點包括三部分內容:結點值、指向結點第一個孩子結點的指針,及指向結點下一個兄弟結點的指針



    樹與森林的遍歷

    樹的遍歷

    樹的遍歷主要有先根遍歷、后根遍歷和層次遍歷(使用的示例樹形結構如下圖)





    先根遍歷:若樹非空,則先訪問根節點,再按從左到右的順序遍歷根結點的每棵子樹。如上圖:RADEBCFGHK

    void treePreOrder(TreeNode *node) {if(node==NULL) return;printf("%d",node->value);for(int i = 0; i< node.child.size(); i++) {treePreOrder(node.child[i]);}return; }

    后根遍歷:若樹非空,按從左到右的順序遍歷根結點的每棵子樹,再訪問根節點。如上圖:DEABGHKFCR

    void treeLastOrder(TreeNode *node){if(node==NULL) return;for(int i = 0; i< node.child.size(); i++) {treePreOrder(node.child[i]);}printf("%d",node->value);return; }

    層次遍歷:

    void treeLayerOrder(TreeNode *node){queue<int> q;q.push_back(node);while(!q.empty()){TreeNode *root = q.front();q.pop();printf("%d",node->value);for(int i = 0; i< node.child.size(); i++) {q.push_back(node.child[i]);}}return; }

    森林遍歷

    1. 先序遍歷森林

  • 訪問森林中第一棵樹的根結點
  • 先序遍歷第一棵樹中根結點的子樹森林
  • 先序遍歷除去第一棵樹之后剩余的樹構成的森林
  • 2. 中序遍歷森林

  • 中序遍歷森林中第一棵樹的根結點的子樹森林
  • 訪問第一棵樹的根結點
  • 中序遍歷除去第一棵樹之后剩余的樹構成的森林
  • 并查集的應用

    并查集是一種樹型的數據結構,用于處理一些不相交集合的合并及查詢問題(森林→樹)。使用雙親表示法

    原始的 parent 列表

    位置0123456789
    結點的值0123456789
    雙親結點-1000-144-177

    合并后parent 列表

    位置0123456789
    結點的值0123456789
    雙親結點-1000044-177


    并查集支持三種操作:1. 初始化,2. 尋找集合,3. 合并集合

    // 初始化 void initialise(int parent[], int len) {for(int i = 0; i < len; i++) {// 記錄當前結點的雙親結點parent[i] = -1;// 記錄當前樹高rank[i] = 1;}return; } // 尋找x的根 int find_node(int x, int parent[]) {int x_node = x;while(parent[x_node]!=-1) {x_node = parent[x_node];}return x_node; } // 合并,在合并的時候,要注意樹的高度,應該把樹低的樹合并到樹高的樹中 int union(int x, int y, int parent[]) {int x_node = find_node(x,parent);int y_node = find_node(y,parent);// 在同一個集合里if(x_node==y_node) {return 0;} eles {// 不在同一個集合里if(rank[x_node] > rank[y_node]) {parent[y_node] = x_node;} else (rank[x_node] < rank[y_node]) {parent[x_node] = y_node} else {parent[x_node] = y_node; // x_node的父節點在y_node的位置里rank[y_node]++;}return 1;} }

    總結

    以上是生活随笔為你收集整理的【数据结构-树】1.树与森林(树的遍历、树的存储方法、并查集的实现)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。