數據結構 學習筆記 樹

一、樹的定義

樹的遞歸定義:

1.有且只有一個結點叫根。

2.除根結點外其餘結點可劃分爲m個互不相交的子集T1,T2...Tm(m>=0),並且這m個子集每個子集本身又構成一棵樹,稱爲T的子樹。

 

樹的表示方法有很多,如圖形表示,廣義表表示,嵌套集合表示,凹入表表示等等。

 

樹的基本概念和術語

1.結點

又稱作節點,表示數據元素,鏈式儲存結構要加上相關指針。

2.結點的度Degree

結點的子樹個數或者分枝數,稱爲結點的度。

3.樹的度

樹內各結點的度的最大值。

4.葉子結點

度爲0的結點稱爲葉子結點,或者終端結點。

5.分支結點

指的是度不爲0的結點,或者有子樹的結點。

6.結點的層次

此處規定根結點的層次爲1,其他結點的層次數等於父親結點+1。結點的層次也叫結點的深度。

7.樹的高度(Depth)

樹中各結點的最大層次數,稱爲樹的高度。

8.孩子結點

當前結點所有子樹的根結點,稱爲孩子結點。

9.後裔結點

當前結點爲跟結點,其子樹上的所有結點,都是當前結點的後裔結點。

10.雙親結點

即父親結點。

11.祖先結點

從根結點由路徑到達當前結點,路徑經過的所有結點,均爲當前結點的祖先結點。

12.兄弟結點(Silbling)

雙親結點相同的所有結點互稱爲兄弟結點。

13.堂兄弟結點

雙親結點在同一層次(深度相同)的結點,互爲堂兄弟。

14.有序樹和無序樹

同一結點的所有子樹,從左至右規定次序叫有序樹,若結點的子樹不分先後次序即無序樹。

15.森林

m棵不相交樹的集合,叫做森林。

與線性表以及其他結構相比,樹結構有明顯的差異,每個結點至多有一個直接前驅,但卻可以有多個後繼。

 

二、二叉樹

2.1遞歸定義

二叉樹是n個結點的有限集合,其中n>=0,n=0 稱爲空樹否則:

1.有且只有一個結點爲根結點。

2.其餘結點劃分爲兩個互不相交的子集TL,TR,並且TL,TR分別構成一棵二叉樹,稱爲T的左子樹和右子樹。

2.2特點

特點一、二叉樹中的每個結點最多隻有兩棵子樹。即二叉樹中僅僅存在三種度數的結點:0度,1度,2度。

特點二、二叉樹是一棵有序樹,其子樹區分左右。

例如:3個結點構成的樹 只有2種形態,而3個結點構成的二叉樹形態 有 5 種

 

2.3二叉樹的性質

定義:

滿二叉樹:每層都有最大數目結點的二叉樹

完全二叉樹:在滿二叉樹最下層自右向左連續刪除若干結點形成的樹

性質一:二叉樹上第i層上的結點樹\leq 2^{i-1}(i> 0)

性質二:深度爲k的二叉樹的結點樹\leq 2^k -1(k> 0)

性質三:對於任意非空二叉樹,如果其葉子樹爲N0,度爲2的結點樹爲N2,則有下列等式:n_{0} = n_{2} + 1

證明略。

性質四:有n個結點的完全二叉樹的深度爲log_{2}n + 1 (向下取整)

性質五:在編號的完全二叉樹中,當前結點的編號爲i,則有:

1.如果i的左孩子存在,其編號爲2i

2.如果i的右孩子存在,其編號爲2i+1

3.如果i的父親結點存在,其編號爲i/2 向下取整

 

例題:已知完全二叉樹有100個結點,則該二叉樹有多少個葉子結點?

(至少三種方法)

方法一:最大編號爲100,其父結點爲50,從51~100均爲葉子結點。ANS = 100 - 51 + 1 = 50.

 

 

2.4二叉樹的存儲結構

2.4.1順序存儲結構

(1)完全二叉樹的順序存儲

用數組存儲元素(結點的值),用數組下標編號表示樹中對應結點的編號值。

(2)一般二叉樹的順序存儲

將其補全爲完全二叉樹後按照完全二叉樹進行存儲。

 

2.4.2鏈表存儲結構

二叉鏈表

typedef struct BNode{
    char data;
    struct BNode *lChild, *rChild;
}BiNode;

二叉鏈表是最基本的鏈式存儲結構,一棵n個結點的二叉樹,採用二叉鏈表存儲的時候,共有2n個指針域,其中有n-1個指針非空(除了根結點,其他結點都有指針指向,剩下2n-(n-1) = n+1個指針域爲空。

 

三叉鏈表

每個結點有三個指針域(左右孩子,父結點),稱這種結構的鏈表叫做三叉鏈表。

typedef struct TriNode{
    char data;
    struct Trinode *lChird, *rChild, *parent;
}TNode;

 

2.5 二叉樹的遍歷

遍歷即對二叉樹中的每個結點經過一次且僅一次的訪問。

二叉樹訪問次序組合

                                  從左到右                   從右到左

先序                              DLR                          DRL

中序                              LDR                          RDL

後序                              LRD                          RLD

 

在此使用從左到右的遍歷序。

1.先序遍歷 DLR

if(T){
    首先訪問根結點;
    先序遍歷T的左子樹;
    先序遍歷T的右子樹;
}

2.中序遍歷 LDR

if(T) {
    中序遍歷T的左子樹;
    訪問T的根結點;
    中序遍歷T的右子樹;
}

3.後序遍歷 LRD

if(T) {
    後序遍歷T的左子樹;
    後序遍歷T的右子樹;
    訪問T的根結點;
}

 

此處需要練習,請自行練習。

例:某序列遍歷如下:

中序:CBEDAGHFJI

後序:CEDBHGJIFA

試構造其二叉樹結構。

 

先序遍歷的遞歸算法

void preOrder(BNode *T) {
    if(T) {
        cout << T->data << endl;
        preOrder(T->lChild);
        preOrder(T->rChild);
    }
}

先序遍歷的非遞歸算法

void preOrderNR(BiNode *T) {
    BiNode *p;
    stack<BiNode*> s;
    p = T;
    while(p || s.empty()) {
        if(p) {
            cout << p->data << " ";
            s.push(p);
            p = p->lChild;
        }
        else {
            s.pop();
            p = p->rChild;
        }
    }
}

2.6二叉樹的創建和銷燬

void createSubTree(BiNode *q, int k) { // 子樹創建
    //q爲當前跟結點
    //k = 1爲左子樹,k = 2爲右子樹
    BiNode *u;
    int x;
    cin >> x;
    if(x != '/') {
        u = new BiNode;
        u->data = x;
        u->lChild = NULL;
        u->rChild = NULL;
        if(k == 1) 
            q ->lChild = u;
        else if(k == 2)
            q ->rChild = u;
        createSubTree(u,1);
        createSubTree(u,2);
    }
}

void createBiTree(BiNode *&T) {
    BiNode *p;
    char x;
    cout << "請按照先序序列輸入二叉樹,'/'表示無子樹" << endl;
    cin >> x;
    if(x = '/')  
        return;
    T = new BiNode;
    T->data = x;
    T->lChild = NULL;
    T->rChild = NULL;
    p = T;
    createSubTree(p, 1);
    createSubTree(p, 2);
}

創建如圖

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章