一、樹的定義
樹的遞歸定義:
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層上的結點樹
性質二:深度爲k的二叉樹的結點樹
性質三:對於任意非空二叉樹,如果其葉子樹爲N0,度爲2的結點樹爲N2,則有下列等式:
證明略。
性質四:有n個結點的完全二叉樹的深度爲 (向下取整)
性質五:在編號的完全二叉樹中,當前結點的編號爲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);
}
創建如圖