數據結構-樹

二叉樹

  1. 每個結點最多有兩顆子樹,結點的度最大爲2
  2. 左子樹和右子樹是有順序的,次序不能顛倒
  3. 節點數爲n的樹 深度至多爲n 至少爲log2(n+1)向下取整
  4. 對於任何一棵非空的二叉樹,如果葉節點個數爲n0,度數爲2的節點個數爲n2,則有: n0 = n2 + 1

存儲二叉樹結構的方法一般有三種,數組、鏈表、遊標

滿二叉樹

高度爲h的滿二叉樹擁有剛剛好(2^h+1 )-1個節點

完全二叉樹

若二叉樹高度爲h,除h層外其他所有層節點個數都達到了最大個數。若h層有葉節點,則所有的葉節點從左到右排列。這就是完全二叉樹

  1. 具有n的結點的完全二叉樹的深度爲log2n+1.

  2. 如果有一顆有n個節點的完全二叉樹的節點按層次序編號,對任一層的節點i(1<=i<=n)有

    • 如果i=1,則節點是二叉樹的根,無雙親,如果i>1,則其雙親節點爲[i/2],向下取整
    • 如果2i>n那麼節點i沒有左孩子,否則其左孩子爲2i
    • 如果2i+1>n那麼節點沒有右孩子,否則右孩子爲2i+1

    tips: 編號後,左子節點的編號是父節點編號的兩倍

    參考

二叉樹的遍歷

屏幕快照 2017-12-19 下午6.20.43.png

前序遍歷:根—左—右。

  • 遞歸實現

  • 非遞歸實現

    思路:每次訪問樹的左節點,並將節點入棧。如果左節點爲空,就取棧頂出棧,訪問棧頂節點的右節點,並繼續訪問入棧訪問左節點。代碼如下:

void preOrderTraverse(Tree t) {
    Stack s; 
    Tree tmp = t;
	
    while((tmp != NULL) || !isEmpty(&s)) {
        while(tmp != NULL) {
            Push(&s, tmp);
            visit(&tmp);
            tmp = tmp->lchild;
        }
        if(!isEmpty(&s)) {
            Pop(&s, &tmp);
            tmp = tmp->rchild;
        }
    }
}

中序遍歷: 左-根-右

  • 遞歸實現

  • 非遞歸實現

    1. 若其左孩子不爲空,則將t入棧,並將t的左孩子設置爲當前的t
    2. 若其左孩子爲空,則取棧頂元素並進行出棧操作,訪問該結點。然後將當前的t置爲棧頂結點的右孩子
    3. 直到t爲空並且棧爲空,則遍歷結束。
void inOrderTraverse(Tree t) {
    Stack s; 
    Tree tmp = t;
	
    while((tmp != NULL) || !isEmpty(&s)) {
        while(tmp != NULL) {
            Push(&s, tmp);
            tmp = tmp->lchild;
        }
        
        if(!isEmpty(&s)) {
            Pop(&s, &tmp);
            visit(&tmp);
            tmp = tmp->rchild;
        }
    }
}

後序遍歷: 左-右-根

  • 遞歸實現

  • 非遞歸實現

    確保在訪問父節點之前左右子節點都已經被訪問。當前節點如果沒有子節點,或者當前節點的子節點都被訪問的時候,可以訪問當前節點。否則將當前節點的子節點入棧。

void postOrderTraverse(Tree t) {
    Stack s; 
    Tree cur = NULL;
    Tree pre = NULL;

	Push(&s, t);
    while(!isEmpty(&s) {
    	 Top(&s, &cur);
        if((cur->lchild == NULL && cur->rchild == NULL)) ||
        		(cur->lchild == NULL && pre != NULL && pre == cur->rchild) ||
        		(cur->rchild == NULL && pre != NULL && pre == cur->lchild)) {
        		Pop(&s, &cur);
        		visit(cur);
        		pre = cur;		
        } else {
        		if(cur->lchild) {
        			Push(&s, cur->lchild);
        		}
        		if(cur->rchild) {
        			Push(&s, cur->rchild);
        		}
        	}
        }
    }
}

二叉樹的創建

  1. 使用訪問序列建立二叉樹,如 先序:ABDCEGFHI 中序:DBAEGCHFI

    屏幕快照 2017-12-19 下午9.12.37.png

    tips: 如果僅僅知道二叉樹的先序遍歷和後序遍歷,無法確定二叉樹

  2. 使用廣義表來構造,如:A(B(D), C(E( ,G), F(H,I)))

    屏幕快照 2017-12-19 下午9.12.37.png

線索樹

n個結點的二叉樹有2n個鏈域,其中真正有用的是n – 1個,其它n + 1個都是空域。 爲了充分利用結點中的空域,使得對某些運算更快,如前驅或後繼等運算。

屏幕快照 2017-12-19 下午9.37.08.png

二叉樹的應用:霍夫曼樹

參考這裏
https://blog.csdn.net/shuangde800/article/details/7341289

主要有兩類:

  • 霍夫曼樹構造條件判斷樹,使其比較次數最少
  • 霍夫曼編碼
發佈了32 篇原創文章 · 獲贊 60 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章