https://blog.csdn.net/lin20044140410/article/details/89436835 二叉樹鏈式存儲
數據結構-樹
樹是一種一對多的數據結構,是n(n>=0)個結點的有限集。N=0時爲空樹。在任意一棵非空樹中:1,有且只有一個特定的稱爲根root的結點,2,當n>1時,其餘結點可分爲m (m>0)個互不相交的有限集T1,T2,,,,Tm,其中每一個集合本身又是一棵樹,並且稱爲根的子樹。
一些概念:
- 結點擁有的子樹數稱爲階段的度,度爲0的結點稱爲葉結點Leaf,度不爲0的結點稱爲分支結點。樹的度是樹內個結點的度的最大值。
- 結點的層次,從根開始,根爲第一層,根的孩子爲第二層,樹中結點的最大層次稱爲樹的深度,或者高度。
二叉樹
二叉樹是一種特殊結構的樹,是n個結點的有限集合,或者爲空樹,或者由一個根結點和兩棵互不相交的、分別稱爲左子樹和右子樹的二叉樹組成。
二叉樹的特點:
- 每個結點最多兩棵子樹,
- 左子樹、右子樹是有順序的,次序不能顛倒,
- 即使樹中某結點只有一棵子樹,也要區分它是左子樹還是右子樹。
特殊的二叉樹
斜樹,所有的結點都只有左子樹的二叉樹叫左斜樹,所有結點都只有右子樹的二叉樹叫右斜樹。斜樹,其實就是線性表結構。
滿二叉樹,在一棵二叉樹中,如果所有分支結點都存在左子樹和右子樹,並且所有葉子都在同一層上,這樣的二叉樹稱爲滿二叉樹。
滿二叉樹特點:
- 葉子只能出現在最下一層,
- 非葉子結點的度一定是2
- 在同樣深度的二叉樹中,滿二叉樹的結點個數最多,葉子最多。
完全二叉樹
對一棵具有n個結點的二叉樹按層序編號,如果編號爲i(1<=i<=n)的結點與同樣深度的滿二叉樹中編號爲i的結點在二叉樹中位置完全相同,則這棵二叉樹稱爲完全二叉樹。
滿二叉樹一定是一棵完全二叉樹,但是完全二叉樹不一定是滿的。
完全二叉樹的所有結點與同樣深度的滿二叉樹,它們按層序編號相同的結點,是一一對應的。
上圖是一棵完全二叉樹。
圖中樹1,樹2,樹3因爲編號不連續,都不是完全二叉樹,
完全二叉樹特點:
- 葉子結點只能出現在最下兩層。
- 最下層葉子結點一定集中在左部連續位置。
- 倒數第二層,如有葉子結點,一定都在右部連續位置。
- 如果結點度爲1,則該節點只有左孩子,不存在只有右子樹的情況。
- 同樣結點數的二叉樹,完全二叉樹深度最小。
判斷一棵二叉樹是不是完全二叉樹,就是給每個結點按照滿二叉樹的結構逐層編號,如果編號出現空擋,就不是完全二叉樹。
二叉樹的性質
- 在二叉樹的第i層,至多有2(i-1) (i>=1)
- 深度是k的二叉樹,最多有2k -1 個結點 k>=1.
以上兩點都可以通過數據歸納法來得出結論。
- 任意一棵二叉樹,如果終端結點數爲n0,度爲2的結點數爲n2,則n0 = n2 +1,
- 具有n個結點的完全二叉樹的深度爲log2n +1
- 如果對一棵有n個結點的完全二叉樹(深度爲log2n +1)的結點,按層序編號(從第1層到第log2n +1 層,每層從左到右),對於任一結點i(1<=I <=n):
如果i = 1,結點i就是二叉樹的根,無雙親,如果i>1,則其雙親是結點 i/2 (向下取整)。
如果2i >n,則結點i無左孩子,結點i爲葉子結點;否則其左孩子是結點2i。
如果2i + 1 > n,則結點i無右孩子,否則其右孩子是結點2i + 1。
依據以上性質,來定義二叉樹的存儲結構,先說順序存儲。
二叉樹的順序存儲結構就是用一維數組存儲二叉樹中的結點,結點的存儲位置,就是數組的下標,相應位置不存在的結點設置爲null。這種存儲結構,適用於完全二叉樹,因爲對於極端的右斜樹,它有k個結點,卻要分配2k -1個存儲空間,這是對存儲空間的浪費。
二叉樹的鏈式存儲結構,每個結點最多兩個孩子,所以這種存儲結構,一個數據域,兩個指針域,兩個指針域存放指向左孩子和右孩子的指針,稱這樣的存儲結構爲二叉鏈表。
二叉樹的遍歷
對二叉樹的遍歷,就是把樹中的結點變成某種意義的線性序列。
遍歷算法就是遞歸。
- 前序遍歷,若二叉樹爲null,則空操作返回,否則先訪問根結點,然後前序遍歷左子樹,在前序遍歷右子樹。
- 中序遍歷,若樹爲null,則空操作返回,否則從根結點開始,中序遍歷左子樹,然後訪問根結點,最後中序遍歷右子樹。
- 後序遍歷,若樹爲null,則空操作返回,否則從左到右,先葉子後結點的方式,先遍歷訪問左子樹,再同樣從左到右,先葉子後結點的方式,遍歷右子樹,最後訪問根結點。
- 層序遍歷,若樹爲null,則空操作返回,否則從樹的第一層根結點開始訪問,從上到下逐層遍歷,在同一層中,按從左到右的順序對結點逐個訪問。
從遍歷操作可以得出,
已知前序遍歷序列和中序遍歷序列,可以唯一確定一棵二叉樹;
已知後序遍歷序列和中序遍歷序列,可以唯一確定一棵二叉樹;
這兩種情況都可以確定根結點,並且可以確定左子樹或者右子樹。
但是,已知前序和後序序列,是不能確定一棵二叉樹的,因爲雖然根結點可以確定,但是無法確定那個結點是左子樹,那個結點是右子樹。
二叉樹順序存儲代碼實現:
#ifndef DATA_STRUCTURE_BINARY_TREE_CLASS_H
#define DATA_STRUCTURE_BINARY_TREE_CLASS_H
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 //存儲空間初始分配量
#define MAX_TREE_SIZE 100 //二叉樹最大結點樹
typedef int Status; //表示函數結果的狀態碼
typedef int TElemType; //樹節點的數據類型,暫定int
typedef TElemType SqBiTree[MAX_TREE_SIZE]; //順序存儲結構數組
typedef struct {
int level;//節點的層
int order;//本層的序號,按滿二叉樹計算
}Position;
TElemType Nil = 0; //表示空元素
#endif
#include "binaryTree.h"
#include "iostream"
#include "cstdlib"
#include "cmath"
using namespace std;
Status visit(TElemType c) {
cout << "node:" << c <<endl;
}
//構造空二叉樹
Status InitBiTree(SqBiTree T) {
int i;
for (i = 0; i< MAX_TREE_SIZE; i++) {
T[i] = Nil;//空值
}
return OK;
}
Status CreateBiTree(SqBiTree T) {
int i=0;
cout<< "按層序輸入結點的值,整形數,0表示空結點,結點數 <=" <<
MAX_TREE_SIZE <<endl;
//對前10個結點賦值
while (i < 10) {
T[i] = i+1;
cout << "結點:" << i <<",值:"<< T[i] << endl;
//對於非根結點,一定有雙親,如果沒有就出錯了
if (i != 0 && T[(i+1)/2 -1] == Nil && T[i] != Nil) {
cout << "無雙親的非根結點:" << T[i] << endl;
exit(ERROR);
}
i++;
}
//其餘結點賦值空
while(i < MAX_TREE_SIZE) {
T[i] = Nil;
i++;
}
return OK;
}
//判空樹
Status BiTreeEmpty(SqBiTree T) {
//如果根結點爲空,即空樹
if (T[0] == Nil) {
return TRUE;
} else {
return FALSE;
}
}
//獲取樹的深度
int BiTreeDepth(SqBiTree T) {
int i,j=-1;
for (i = MAX_TREE_SIZE-1; i>=0; i--) {
if (T[i] != Nil) {//找到最後一個不爲空的結點
break;
}
}
//因爲在找到最後一個非空結點後,for又做了一次i--,所以要在加回去
i++;
//根據前面的性質,深度爲k二叉樹,最多有2k(2的k次冪) -1 個結點,
//現在知道結點數,反推深度
do{
j++;
}while (i>=powl(2,j));
return j;
}
//獲取根結點
Status Root(SqBiTree T, TElemType *e) {
if (BiTreeEmpty(T)) {
return ERROR;
} else {
*e = T[0];
return OK;
}
}
//獲取指定位置的結點,參數e包含結點所在的層,及本層的序號。
TElemType Value(SqBiTree T, Position e) {
return T[(int)powl(2, e.level -1) + e.order -2];
}
//給指定位置的結點賦值
Status Assign(SqBiTree T, Position e, TElemType value) {
//獲取數組的序號
int i = (int)powl(2, e.level -1) + e.order -2;
if (value != Nil && T[(i+1)/2-1] == Nil) {
//非根結點,無雙親
return ERROR;
} else if (value == Nil && (T[i*2+1] !=Nil || T[i*2+2] !=Nil)) {
//左孩子或者右孩子不爲空,就不能給其雙親賦值空
return ERROR;
}
T[i] = value;
return OK;
}
//返回結點的雙親
TElemType Parent(SqBiTree T, TElemType e) {
int i;
if (T[0] == Nil) {
return Nil;
}
for (i = 1; i<MAX_TREE_SIZE-1; i++) {
if (T[i] == e) {
return T[(i+1)/2-1];
}
}
return Nil;
}
//返回左孩子
TElemType LeftChild(SqBiTree T, TElemType e) {
int i;
if (T[0] == Nil) {
return Nil;
}
for (i =0; i<= MAX_TREE_SIZE -1; i++) {
if (T[i] == e) {
return T[i*2 +1];
}
}
return Nil;
}
//返回右孩子
TElemType RightChild(SqBiTree T, TElemType e) {
int i;
if (T[0] == Nil) {
return Nil;
}
for (i =0; i<= MAX_TREE_SIZE -1; i++) {
if (T[i] == e) {
return T[i*2 +2];
}
}
return Nil;
}
//前序遍歷
void PreTraverse(SqBiTree T, int e) {
visit(T[e]);
if (T[2*e +1] != Nil) {
PreTraverse(T, 2*e+1);
}
if (T[2*e +2] != Nil) {
PreTraverse(T, 2*e+2);
}
}
Status PreOrderTraverse(SqBiTree T) {
cout << "前序遍歷。。。" << endl;
if (!BiTreeEmpty(T)) {
PreTraverse(T, 0);
}
return OK;
}
//中序遍歷
void InTraverse(SqBiTree T, int e) {
if (T[2*e +1] != Nil) {
InTraverse(T, 2*e+1);
}
visit(T[e]);
if (T[2*e +2] != Nil) {
InTraverse(T, 2*e+2);
}
}
Status InOrderTraverse(SqBiTree T) {
cout << "中序遍歷。。。" << endl;
if (!BiTreeEmpty(T)) {
InTraverse(T, 0);
}
return OK;
}
//後序遍歷
void PostTraverse(SqBiTree T, int e) {
if (T[2*e +1] != Nil) {
PostTraverse(T, 2*e+1);
}
if (T[2*e +2] != Nil) {
PostTraverse(T, 2*e+2);
}
visit(T[e]);
}
Status PostOrderTraverse(SqBiTree T) {
cout << "後序遍歷。。。" << endl;
if (!BiTreeEmpty(T)) {
PostTraverse(T, 0);
}
return OK;
}
//層序遍歷
void LevelOrderTraverse(SqBiTree T) {
int i = MAX_TREE_SIZE -1;
cout << "層序遍歷。。。" << endl;
while (T[i] == Nil) {
i--;//查找最後一個非空結點
}
cout << "最後一個非空結點(數組小標從0開始):" << i << endl;
for (int j=0; j<=i; j++) {
if(T[j] != Nil) {
visit(T[j]);
}
}
cout << endl;
}
//按層輸出結點
void LevelOrderVisist(SqBiTree T) {
int j,k;
Position p;
TElemType e;
cout << "按層輸出結點。。。" << endl;
for (j=1;j<=BiTreeDepth(T);j++) {
cout <<"第 "<<j <<"層:" <<endl;
for (k=1;k<=powl(2,j-1);k++) {
p.level = j;
p.order =k;
e= Value(T,p);
if (e != Nil) {
cout << k << ":" << e << endl;
}
}
cout <<endl;
}
}
int main() {
Status i;
Position p;
TElemType e;
SqBiTree T;
InitBiTree(T);
CreateBiTree(T);
cout << "新建的二叉樹,深度:" << BiTreeDepth(T) << endl;
i = Root(T, &e);
cout << "二叉樹的根:" << e << endl;
LevelOrderVisist(T);
LevelOrderTraverse(T);
PreOrderTraverse(T);
InOrderTraverse(T);
PostOrderTraverse(T);
p.level = 3;
p.order = 2;
e = Value(T, p);
cout << "修改第3層第2個結點的值,原值:"<< e << "新值爲50." << endl;
e = 50;
Assign(T, p, e);
e = Value(T, p);
cout << "修改後的第3層第2個結點的值:"<< e << endl;
PreOrderTraverse(T);
return 0;
}
/**output/
$ g++ -g BinaryTree.cpp -o BiTree
$ ./BiTree
按層序輸入結點的值,整形數,0表示空結點,結點數 <=100
結點:0,值:1
結點:1,值:2
結點:2,值:3
結點:3,值:4
結點:4,值:5
結點:5,值:6
結點:6,值:7
結點:7,值:8
結點:8,值:9
結點:9,值:10
新建的二叉樹,深度:4
二叉樹的根:1
按層輸出結點。。。
第 1層:
1:1
第 2層:
1:2
2:3
第 3層:
1:4
2:5
3:6
4:7
第 4層:
1:8
2:9
3:10
層序遍歷。。。
最後一個非空結點(數組小標從0開始):9
node:1
node:2
node:3
node:4
node:5
node:6
node:7
node:8
node:9
node:10
前序遍歷。。。
node:1
node:2
node:4
node:8
node:9
node:5
node:10
node:3
node:6
node:7
中序遍歷。。。
node:8
node:4
node:9
node:2
node:10
node:5
node:1
node:6
node:3
node:7
後序遍歷。。。
node:8
node:9
node:4
node:10
node:5
node:2
node:6
node:7
node:3
node:1
修改第3層第2個結點的值,原值:5新值爲50.
修改後的第3層第2個結點的值:50
前序遍歷。。。
node:1
node:2
node:4
node:8
node:9
node:50
node:10
node:3
node:6
node:7