1. 程式人生 > >資料結構與演算法-二叉樹

資料結構與演算法-二叉樹

簡介

二叉樹是一種非常重要的非線性結構,比較適合用於計算機處理,而且任何樹和森林都可以轉換為二叉樹。

定義

一棵二叉樹Tn(n0)個結點的有限集合。當n=0時,它是一棵空二叉樹;當n>0時,它由一個根節點和兩棵分別稱為左子樹和右子樹且互不相交的二叉樹組成。 二叉樹的遞迴定義如下:

T={,n=0{root,TL,TR},n>0 其中root表示T的根,TL表示T的左子樹,T
R
表示T的右子樹,TLTR仍是二叉樹。

二叉樹中即使只有一棵子樹也要進行區分,說明它是左子樹,還是右子樹,這時二叉樹與樹的最主要的區別。二叉樹就是結點度為2的樹是錯誤的!

五種基本形態

(a):空樹 (b):只有根節點(b) (c):只有左子樹(c) (d):只有右子樹(d) (e):既有左子樹,又有右子樹(e)

性質

  1. 在二叉樹的第i(i1)層上之多有2i1個結點。
  2. 深度為k(k1)的二叉樹之多有2k1個結點。
  3. 對任何一棵非空二叉樹,如果其葉子結點數為n0,度為2的節點數為n2,則n0=
    n2+1
  4. 具有n(n>0)個結點的完全二叉樹的深度為log2n+1
  5. 如果將一棵有n個結點的完全二叉樹按照自頂向下,同一層自左向右的順序連續給結點編號1,2,3,...,n,然後按此結點編號將樹中各結點順序地存放於一個一維陣列中, 並簡稱編號為i的結點為結點 i(1in)。則有以下關係:

(1)若i=1,則結點i為根,無雙親結點;若i>1, 則i的雙親結點為結點i/2。 (2)若2in, 則結點i的左孩子為結點2i;否則結點i無左孩子。 (3)若

2i+1n, 則結點i的右孩子為結點2i+1,否則,結點i無右孩子。

遍歷方式

  • 遍歷二叉樹:指遵從某種順序,順著某一條搜尋路徑訪問二叉樹中的各個結點,使得每個結點均被訪問一次,而且僅被訪問一次。
  • 訪問:輸出結點的資訊、修改結點的資料值等,但一般要求這種訪問不破壞原來資料之間的邏輯結構。

先序遍歷

也稱為前序遍歷,按照“根-左子樹-右子樹”的次序遍歷二叉樹。(遞迴) 如果二叉樹為空,則遍歷結束;否則: 1. 訪問根節點(D); 2. 先序遍歷左子樹(L); 3. 先序遍歷右子樹(R)。

void preTraverse(BiTree T) {
    if (T) {
        cout << T->data << " ";
        preTraverse(T->lchild);
        preTraverse(T->rchild);
    }
}

中序遍歷

按照“左子樹-根-右子樹”的次序遍歷二叉樹。(遞迴) 如果二叉樹為空,則遍歷結束;否則: 1. 中序遍歷左子樹(L); 2. 訪問根節點(D); 3. 中序遍歷右子樹(R)。

void midTraverse(BiTree T) {
    if (T) {
        midTraverse(T->lchild);
        cout << T->data << " ";
        midTraverse(T->rchild);
    }
}

後序遍歷

按照“左子樹-右子樹-根”的次序遍歷二叉樹。(遞迴) 如果二叉樹為空,則遍歷結束;否則: 1. 後序遍歷左子樹(L); 2. 後序遍歷右子樹(R)。 3. 訪問根節點(D);

void postTraverse(BiTree T) {
    if (T) {
        postTraverse(T->lchild);
        postTraverse(T->rchild);
        cout << T->data << " ";
    }
}

層次遍歷

按照二叉樹的層次,從上到下、從左到右的次序訪問各節點。(佇列) 層次遍歷從二叉樹的根節點開始,首先將根結點指標入隊,然後從隊頭取出一個數據元素執行以下操作: 1. 訪問該指標所指結點; 2. 若該指標所指結點的左、右孩子結點不空,則將其左孩子指標和右孩子指標入隊; 3. 重複上述1、2兩個步驟,直至佇列為空。

void levelTraverse(BiTree T) {
    BiTree bt;
    LinkQuene q;
    if (T) {
        q.EnQuene(T);
        while (q.QueneEmpty()) {
            bt = q.DeQuene();
            if (bt)
                cout << bt->data << " ";
            if (bt->lchild)
                q.EnQuene(bt->lchild);
            if (bt->rchild)
                q.EnQuene(bt->rchild);
        }
    }
}

整體實現

#include "pch.h"
#include <iostream>
#include <stdlib.h>
#define ElemType BiTree 
#define ERROR -1
#define OK 0
using namespace std;

//二叉樹結點
typedef struct node {
    struct node *lchild;
    struct node *rchild;
    char data;
} BiTreeNode, *BiTree;

struct Node {
    ElemType data;
    Node* next;
};

class LinkQuene {
private:
    Node* front;
    Node* rear;
public:
    LinkQuene();
    ~LinkQuene();
    int EnQuene(ElemType);
    ElemType DeQuene();
    int QueneEmpty();
};

LinkQuene::LinkQuene() {
    front = new Node;
    front->next = NULL;
    rear = front;
    //rear->next=NULL; 
}

LinkQuene::~LinkQuene() {
    Node *p;
    while (front) {
        p = front;
        front = front->next;
        delete p;
    }
}

int LinkQuene::EnQuene(ElemType c) {
    Node *p;
    p = new Node;
    p->data = c;
    p->next = NULL;
    rear->next = p;
    rear = p;
    if (front->next == NULL)
        front->next = p;
    return OK;
}

ElemType LinkQuene::DeQuene() {
    Node *p;
    ElemType c;
    if (rear == front) {
        cout << "?????";
        return NULL;
    }
    p = front->next;
    c = p->data;
    front->next = p->next;
    if (p->next = NULL)
        front = rear;
    delete p;
    return c;
}


int LinkQuene::QueneEmpty() {
    int i = 0;
    if (front->next != NULL)
        i = 1;
    return i;
}

//前序遍歷
void preTraverse(BiTree T) {
    if (T) {
        cout << T->data << " ";
        preTraverse(T->lchild);
        preTraverse(T->rchild);
    }
}
//中序遍歷
void midTraverse(BiTree T) {
    if (T) {
        midTraverse(