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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

数据结构---与树相关的知识

發布時間:2024/5/14 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构---与树相关的知识 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

與樹有關的一系列知識: 樹,二叉樹,滿二叉樹,完全二叉樹,文章還沒完,我會后序補充的

  • 一: 樹(了解就行)
    • 1.1 概念
    • 1.2 一些與樹相關的重要概念
    • 1.3 樹的表示形式
  • 二: 二叉樹(非常重要,重點掌握)
    • 2.1 概念
    • 2.2 兩種特殊的二叉樹
      • 2.2.1 滿二叉樹
      • 2.2.2 完全二叉樹
    • 2.3 二叉樹的性質
    • 2.4 二叉樹的基本操作
      • 2.4.1手動快速創建一棵簡單的二叉樹
      • 2.4.2 二叉樹的遍歷
        • a. 前中后序遍歷(遞歸操作)
        • b. 前中后序遍歷(非遞歸)
        • c. 層次遍歷
      • 2.4.3 還原二叉樹
        • a.通過前序和中序的結果還原二叉樹
        • b.通過中序和后序的結果還原二叉樹
        • c.通過層次遍歷的結果還原二叉樹.
      • 2.4.4 二叉樹的基本操作方法

有些圖是網上找的,沒有自己畫

一: 樹(了解就行)

1.1 概念

樹是一種非線性的數據結構,它是由n(n>=0)個有限節點組成的一個具有層次關系的集合.
叫成樹的原因: 看起來像是一棵倒著的樹,它的根朝上,而葉子是朝下的.
樹的一些特點:
a. 有一個特殊的節點,稱為根節點,根節點沒有前驅節點.
b. 除根節點外,其余的節點被分成M(M>0)個互不相交的集合T,T2,T3…Tm,其中每一個集合又是一棵與樹類似的子樹.
c. 一棵n個節點的樹有n-1條邊.
d. 除根節點外,每個節點有且僅有一個父節點
e. 子樹是不能相交的.
f. 樹是遞歸定義的.

1.2 一些與樹相關的重要概念

節點的度: 一個節點含有子樹的個數稱為該節點的度
比如:上圖中節點A的度為2,節點D的度為3.

樹的度: 一顆樹中,所有節點度的最大值稱為樹的度
比如:上圖中樹的度為3

葉子節點或終端節點: 度為0的節點稱為葉子節點或者終端節點
比如:上圖中的葉子節點有:F,G,H,I,J.

雙親節點或父節點: 如果一個節點含有子節點,這個節點就稱為子節點的父節點或者雙親節點.
比如:上圖中的A是B,C的父節點.

孩子節點或子節點: 一個節點含有的子樹的根節點稱為該節點的子節點.
比如:上圖中的B,C是A的孩子節點.

根節點: 樹種沒有雙親的節點.(位于食物鏈頂端的節點)
比如:上圖中的A節點.

節點的層次: 從根開始定義起,根為第一層,根的子節點為第二層,依次類推

樹的高度或深度: 樹中節點的最大層次.
比如:上圖中樹的深度為4

非終端節點或分支節點: 度不為0的節點
比如:上圖中的B,D節點

兄弟節點: 具有相同父節點的節點稱為兄弟節點
比如:上圖中的G,H,I節點

堂兄弟節點: 雙親在同一層的節點互為堂兄弟
比如:上圖中的D,E節點

節點的祖先: 從根節點到該節點所經分支上的所有節點
比如:G節點的祖先節點是A,B,D節點.而A節點是所有節點的祖先節點.

子孫節點: 以某節點為根的子樹中任一節點都稱為該節點的子孫.
比如:上圖中D節點的子孫節點是G,H,I.而所有節點都是A的子孫節點.

森林: 有m(m>0)棵互不相交的樹組成的集合稱為森林.

1.3 樹的表示形式

樹有很多種表現形式,但是最常用的是這里的孩子兄弟表示法
a.雙親表示法

節點既要存儲值域,還必須表示其雙親的位置.
優點: 快速知道該節點的雙親.
缺點: 無法快速知道該節點的孩子.

class Node{int value; //存儲的數據Node parent; //指向父節點 }

b.孩子表示法

節點既要存儲值域,還要表示與孩子之間的關系.
優點: 快速知道該節點的孩子.
缺點: 無法快速知道該節點的雙親

class Node{int value; //存儲的數據Node left; //指向左孩子,常常代表左孩子為根的整棵左子樹Node right; //指向右孩子,常常代表右孩子為根的整棵右子樹 }

c.孩子雙親表示法

將孩子表示法和雙親表示法結合起來了.

class Node{int value; //存儲的數據Node left; //指向左孩子,常常代表左孩子為根的整棵左子樹Node right; //指向右孩子,常常代表右孩子為根的整棵右子樹Node parent; //當前節點的父節點. }

d.孩子兄弟表示法

在這個節點中,既要保存值域,還要保存下一個兄弟在哪一個位置.

class Node{int value; //樹中存儲的數據Node firstChild; //第一個孩子的引用Node nextBrother; //下一個兄弟的引用 }

二: 二叉樹(非常重要,重點掌握)

2.1 概念

滿足: 1.為空樹時,是二叉樹 2.由根節點+左子樹+右子樹組成.

一棵二叉樹是節點的一個有限集合:
a.集合可以為空: 表示這是一棵空樹
b.不為空: 由一個根節點加上兩棵分別稱為左子樹和右子樹的二叉樹組成
c.二叉樹不存在度大于2的節點(此節點的孩子子節點個數只能<=2)
d.二叉樹的子樹有左右之分,次序不能顛倒,依次二叉樹是有序樹.

注意: 對于任意的二叉樹都是由以下集中情況復合而成的.

2.2 兩種特殊的二叉樹

2.2.1 滿二叉樹

一棵二叉樹,如果每層的節點數都能達到最大值,則這棵二叉樹就是滿二叉樹.
如果一棵二叉樹的層數為k,且它的節點數是(2^k)-1,則它也是滿二叉樹.

2.2.2 完全二叉樹

完全二叉樹是由滿二叉樹引出來的.滿二叉樹是一種特殊的完全二叉樹.

設二叉樹的深度為h,除第 h 層外,其它各層 (1~h-1) 的結點數都達到飽和(即1~h-1層為一個滿二叉樹),第 h 層所有的結點都從左往右依次排列,這樣的樹就是完全二叉樹。

完全二叉樹

我們來舉一個例子:看下面這張圖,就不是完全二叉樹,因為E節點只有F一個子節點,但是F子節點沒有排在E節點的左邊

2.3 二叉樹的性質

1.若規定根節點的層數為1,則一棵非空二叉樹的第i層上最多有 2^(i-1) 個節點(i>0).
2.若規定只有根節點的二叉樹的深度為1,則深度為k的文二叉樹的最大節點數是 (2^k)-1(k>=0).
3.對任何一棵二叉樹,如果其葉子幾點個數為n0,度為2的非葉子節點個數為n2,則有n0=n2+1.
4.具有n個結點的完全二叉樹的深度k為

向上取整
5.對于具有n個結點的完全二叉樹,如果按照 從上至下從左至右 的順序對所有節點從0開始編號,則對于序號為i的結點有:

  • 若i>0,雙親序號:(i-1)/2;i=0,i為根結點編號,無雙親結點
  • 若2i+1<n,左孩子序號:2i+1,否則無左孩子
  • 若2i+2<n,右孩子序號:2i+2,否則無右孩子

2.4 二叉樹的基本操作

2.4.1手動快速創建一棵簡單的二叉樹

這段代碼并不是創建二叉樹的方式,真正創建二叉樹方法后序會重點講解.

//孩子表示法來表示二叉樹. public class BinaryTree{public static class BTNode{BTNode left; //引用當前孩子的左孩子BTNode right; //引用當前孩子的右孩子int value; //值域//有參構造方法BTNode(int value){this.value = value;}}private BTNode root; //二叉樹的根節點public void createBinaryTree(){BTNode node1 = new BTNode(1); //創建節點node1,它的值為1BTNode node1 = new BTNode(2);BTNode node1 = new BTNode(3);BTNode node1 = new BTNode(4);BTNode node1 = new BTNode(5);BTNode node1 = new BTNode(6);root = node1; //根節點就是node1節點node1.left = node2; //node1的左孩子是node2node1.right = node4; //node1的右孩子是node4node2.left = node3; //node2的左孩子是node3node4.left = node5; //node4的左孩子是node5node4.right = node6; //node5的右孩子是node6} }

由以上代碼創建出來的二叉樹為下圖所示:

2.4.2 二叉樹的遍歷

例圖:

a. 前中后序遍歷(遞歸操作)

學習二叉樹結構,最簡單的方式就是遍歷.

遍歷: 所謂遍歷是指沿著某條路徑搜索路線,依次對樹中每個節點均做一次且僅做一次訪問.
用N代表根節點,L代表根的左子樹,R代表根的右子樹.則有以下遍歷方式 (用上圖演示)

指的是對節點中的值域進行打印.
NLR:前序遍歷----------------根節點---->根的左子樹---->根的右子樹
1–>2–>3–>4–>5–>6

public void preOrder(BtNode reeRoot){//先判斷是否為空if(treeRoot==null){return;}//1.先遍歷根節點System.out.print(treeRoot.value+" ");//2.再遍歷根節點的左子樹----->根節點的左子樹也是二叉樹(遍歷根的左子樹與遍歷原樹的規則相同)preOrder(treeRoot.left); //遞歸遍歷根的左子樹//3.最后遍歷根節點的右子樹----->根的右子樹也是二叉樹(遍歷根的右子樹與遍歷原樹的規則相同)preOrder(treeRoot.right); //遞歸遍歷根的右子樹 }

LNR:中序遍歷----------------根的左子樹---->根節點---->根的右子樹
3–>2–>1–>5–>4–>6

public void inOrder(BtNode reeRoot){if(treeRoot==null){return;}inOrder(treeRoot.left); System.out.print(treeRoot.value+" ");inOrder(treeRoot.right); }

LRN:后序遍歷----------------根的左子樹---->根的右子樹---->根節點
3–>2–>5–>6–>4–>1

public void postOrder(BtNode reeRoot){if(treeRoot==null){return;}postOrder(treeRoot.left); postOrder(treeRoot.right); System.out.print(treeRoot.value+" "); }

b. 前中后序遍歷(非遞歸)

非遞歸采用的是List的數據結構來進行實現的.
利用棧先進后出的特點來實現前中后序的遍歷,再用list來接收節點的值,最后list中的數據就是遍歷的結果.

注意:在下面我只給了前序遍歷的講解圖,中序和后序遍歷大家自己根據對前序遍歷的理解,對應代碼畫一下,剛好作為一個思考和練習題。

前序遍歷:

a.創建對象List和棧的對象為list,s.
b.用cur標記root節點,然后將cur進行入棧操作.
c.當棧不為空時,節點出棧然后用cur接收.
d.當cur不為空時,將此時cur節點的值add到list中.
e.然后判斷此時的cur有沒有右孩子,有的話就將右孩子進行入棧操作.然后cur指向左孩子
最后重復d過程,當cur為空時再從c過程開始執行.
最后list中存儲的數據就是前序遍歷的結果.文字可能看起來不怎么清楚,我們直接上圖形.
大家一定要對照著下面的代碼去看圖,然后根據代碼自己在紙上畫一遍,才能更好的理解和掌握

當s不為空時,進入whlie循環:



因為此時的cur為null了,所以得從c步驟重新開始再走一遍.s不為null.

public List<Integer> preorderTraversal(TreeNode root) {List<Integer> list=new ArrayList<>();Stack<TreeNode> s=new Stack<>();TreeNode cur=root;s.push(cur);while(!s.empty()){cur=s.pop();while(cur!=null){list.add(cur.val);if(cur.right!=null){s.push(cur.right);}cur=cur.left;}}return list; }

中序遍歷

public List<Integer> inorderTraversal(TreeNode root) {List<Integer> list=new ArrayList<>();if(root==null){//說明是空樹,直接返回一個空的list就行。return list;}TreeNode cur=root;Stack<TreeNode> s=new Stack<>();while(!s.empty()||cur!=null){while(cur!=null){s.push(cur);cur=cur.left;}cur=s.pop();list.add(cur.val);cur=cur.right;}return list; }

后序遍歷

public List<Integer> postorderTraversal(TreeNode root) {List<Integer> list=new ArrayList<>();if(root==null){return list;}TreeNode cur=root;TreeNode prev=null;Stack<TreeNode> s=new Stack<>();while(!s.empty()||cur!=null){while(cur!=null){s.push(cur);cur=cur.left;}TreeNode top=s.peek();if(top.right==null || top.right==prev){list.add(top.val);prev=top;s.pop();}else{cur=top.right;}}return list;}

c. 層次遍歷

從所在二叉樹的根節點出發,首先訪問第一層的樹根節點,然后從左往右訪問第二層的節點,接著是第三層,以此類推,自上而下,自作向右逐層訪問樹的節點的過程就是層序遍歷.

比如上圖經過層次遍歷的結果就是:1--->2--->4--->3--->5--->6.

2.4.3 還原二叉樹

a.通過前序和中序的結果還原二叉樹

還原思想:

前序: 根 左子樹 右子樹—通過前序遍歷結果可以找到二叉樹或者其子樹的根節點
中序: 右子樹 根 左子樹—在中序結果中找到根的位置,根左邊的是左子樹的節點,右邊是右子樹的節點.

來看個例題:

前序遍歷結果: EFHIGJK,中序遍歷結果: HFIEJKG,請還原二叉樹

題解:

我們通過前序遍歷的結果可以得出二叉樹的根節點為E,通過中序遍歷結果可知HFI是根的左子樹,JKG是根的右子樹.

再通過前序遍歷可知左子樹的根節點為F,所以HF的左節點,IF的右節點.

從前序結果當中可知,G是右子樹的根節點,JG的左子樹,然后從中序遍歷可知,KJ的右子樹.
最后還原后的圖形為:

b.通過中序和后序的結果還原二叉樹

還原思想:

后序: 左子樹 右子樹 根----在后序結果中確定二叉樹的根節點.
中序: 右子樹 根 左子樹----在中序結果中找到根的位置,根左邊的是左子樹的節點,右邊是右子樹的節點.

來看個例題:

中序遍歷結果為:badce,后序遍歷結果為:bdeca

題解:

先從后序遍歷結果中確定二叉樹的根節點為a,再從中序結果中得知a的左子樹是b,a的右子樹是dce


從后序結果可知c是右子樹的根節點.從中序結果可知,dc的左子樹,ec的右子樹.

注意:通過前序遍歷結果和后序遍歷結果不能還原出二叉樹.
前序:根 左子樹 右子樹
后序:左子樹 右子樹 根
只能找到根節點,不能確定根節點的左右子樹.

c.通過層次遍歷的結果還原二叉樹.

這個相對來說就很簡單了,自上而下,自左向右進行還原就行.
比如層次遍歷結果是abcde,還原二叉樹.
我們直接給出圖形就行:

2.4.4 二叉樹的基本操作方法

方法名作用
int size(Node root)獲取樹中節點的個數
int getLeafNodeCount(Node root)獲取葉子節點的個數
int getLevelNodeCount(Node root)獲取第k層節點的個數
int getHeight(Node root)獲取二叉樹的高度
Node find(Node root,int value)檢測值為value的元素是否存在
boolean is CompleteTree(Node root)判斷一棵樹是不是完全二叉樹

總結

以上是生活随笔為你收集整理的数据结构---与树相关的知识的全部內容,希望文章能夠幫你解決所遇到的問題。

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