二叉樹:二叉樹是每一個結點最多有兩個子樹的有序樹。node
先來介紹一下二叉樹的一些基本性質吧~ios
二叉樹的性質:算法
1.非空二叉樹上葉子結點數等於雙分支節點數加一。測試
性質1 二叉樹第i層上的結點數目最多爲2i-1(i≥1)。
證實:用數學概括法證實:
概括基礎:i=1時,有2i-1=20=1。由於第1層上只有一個根結點,因此命題成立。
概括假設:假設對全部的j(1≤j<i)命題成立,即第j層上至多有2j-1個結點,證實j=i時命題亦成立。
概括步驟:根據概括假設,第i-1層上至多有2i-2個結點。因爲二叉樹的每一個結點至多有兩個孩子,故第i層上的結點數至可能是第i-1層上的最大結點數的2倍。即j=i時,該層上至多有2×2i-2=2i-1個結點,故命題成立。
性質2 深度爲k的二叉樹至多有2k-1個結點(k≥1)。
證實:在具備相同深度的二叉樹中,僅當每一層都含有最大結點數時,其樹中結點數最多。所以利用性質1可得,深度爲k的二叉樹的結點數至多爲:
20+21+…+2k-1=2k-1spa
等比數列求和公式:
故命題正確。
性質3 在任意-棵二叉樹中,若終端結點的個數爲n0,度爲2的結點數爲n2,則no=n2+1。
證實:由於二叉樹中全部結點的度數均不大於2,因此結點總數(記爲n)應等於0度結點數、1度結點(記爲n1)和2度結點數之和:
n=no+n1+n2 (式子1)
另外一方面,1度結點有一個孩子,2度結點有兩個孩子,故二叉樹中孩子結點總數是:
nl+2n2
樹中只有根結點不是任何結點的孩子,故二叉樹中的結點總數又可表示爲:
n=n1+2n2+1 (式子2)
由式子1和式子2獲得:
no=n2+1
徹底二叉樹(Complete BinaryTree)
若一棵二叉樹至多隻有最下面的兩層上結點的度數能夠小於2,而且最下一層上的結點都集中在該層最左邊的若干位置上,則此二叉樹稱爲徹底二叉樹。
特色:
(1) 滿二叉樹是徹底二叉樹,徹底二叉樹不必定是滿二叉樹。
(2) 在滿二叉樹的最下一層上,從最右邊開始連續刪去若干結點後獲得的二叉樹仍然是一棵徹底二叉樹。
(3) 在徹底二叉樹中,若某個結點沒有左孩子,則它必定沒有右孩子,即該結點必是葉結點。code
性質:對徹底二叉樹中編號爲i的結點(n爲結點數),有:blog
(1)若i<(n/2)(下取整),則編號爲i的節點爲分支節點,不然爲葉子節點。遞歸
(2)若n爲奇數,則每一個分支節點都既有左孩子結點,也有右孩子結點。隊列
(3)若編號爲i的節點有左孩子結點,則左孩子結點的編號爲2i;若編號爲i的節點有右孩子結點,則左孩子結點的編號爲2i+1。ci
(4)除樹根結點外,若一個節點的編號爲i,則它的雙親結點編號爲(i/2)(下取整)
(5)具備n個結點的徹底二叉樹的深度爲log2n+1。
滿二叉樹(FullBinaryTree)
一棵深度爲k且有2k-1個結點的二又樹稱爲滿二叉樹。
滿二叉樹的特色:
(1) 每一層上的結點數都達到最大值。即對給定的高度,它是具備最多結點數的二叉樹。
(2) 滿二叉樹中不存在度數爲1的結點,每一個分支結點均有兩棵高度相同的子樹,且樹葉都在最下一層上。
基本性質講完了,不夠的歡迎補充~~
接下來講說二叉樹的存儲結構及其創建:
順序存儲:用一組地址連續的存儲單元來存放二叉樹的元素。(先肯定好樹中個元素的次序)
肯定次序:編號:層次從上到下,每層從左到右。對於編號爲i的節點,若存在左孩子,則左孩子編號爲2i,若存在右孩子,則編號爲2i+1;
typedef struct
{
elemtype data[maxn];//存放二叉樹的節點值
int n;//元素個數
}sqbtree;
對於徹底二叉樹來講,順序存儲十分合適,能從分利用存儲空間,可是對於通常二叉樹而言,順序存儲使二叉樹的插入刪除等操做十分不方便。所以,咱們引入鏈式存儲:
鏈式存儲:用一個鏈表來存一顆二叉樹。節點定義以下:
typedef struct node
{
elemtype data;//數據元素
struct node *lchild;//指向左孩子
struct node *rchild;//指向右孩子
}BiTree;
知道存儲方法之後咱們就能夠創建二叉樹了:(此處採用鏈式存儲)
BiTree CreateBiTree(){
char ch;
BiTree T;
scanf("%c",&ch);
if(ch=='#')
T=NULL;
else{
T = (BiTree)malloc(sizeof(BiTNode));
T->data = ch;
T->lchild = CreateBiTree();//遞歸建樹(根左右:先序建樹)
T->rchild = CreateBiTree();
}
return T;//返回根節點
}
再來看看二叉樹的三種遍歷方式:
//先序遍歷二叉樹
void PreOrderTraverse(BiTree T){
if(T){
printf("%c",T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
//中序遍歷
void InOrderTraverse(BiTree T){
if(T){
PreOrderTraverse(T->lchild);
printf("%c",T->data);
PreOrderTraverse(T->rchild);
}
}
//後序遍歷
void PostOrderTraverse(BiTree T){
if(T){
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
printf("%c",T->data);
}
}
以上均採用遞歸的方式遍歷,下面是非遞歸的方式:(利用棧)
1 //棧的鏈式存儲結構 2 typedef struct LNode 3 { 4 BiTree data; 5 struct LNode *next; 6 }LNode,*LinkList; 7 8 //進棧 9 Status Push(LinkList& S,BiTree T) 10 { 11 LinkList stack; 12 stack=(LinkList)malloc(sizeof(LNode)); //分配空間 13 stack->data=T; 14 stack->next=S->next; //進棧 15 S->next=stack; 16 return OK; 17 18 }//Push 19 //出棧 20 Status Pop(LinkList &S,BiTree &T) 21 { 22 LinkList stack; 23 stack=S->next; //出棧 24 S->next=stack->next; //棧頂指向下個元素 25 T=stack->data; 26 return OK; 27 }//Pop 28 //是否爲空棧 29 Status StackEmpty(LinkList S) 30 { 31 if(S->next==NULL) 32 return OK; 33 else 34 return ERROR; 35 } 36 37 //先序非遞歸遍歷 算法1 38 void PreOrder1(BiTree T) 39 { 40 BiTree Stack[MaxSize],p; //定義棧 41 int top=0; 42 p=T; 43 while (p!=NULL||top>0) 44 { 45 while(p!=NULL) 46 { 47 cout<<p->data<<" "; //輸出結點data 48 Stack[top]=p; //左樹進棧 49 top++; 50 p=p->lchild; 51 } 52 if(top>0) 53 { 54 top--; 55 p=Stack[top]; 56 p=p->rchild; 57 } 58 } 59 cout<<endl; 60 } 61 //先序遍歷非遞歸 算法2 62 void PreOrder2(BiTree b) 63 { 64 LinkList stack; 65 BiTree p; 66 p=(BiTree)malloc(sizeof(BiTree)); 67 68 69 stack=(LinkList)malloc(sizeof(LinkList)); 70 stack->next=NULL; 71 Push(stack,b); //二叉樹頭結點進棧 72 while(!StackEmpty(stack)) //是否爲空 73 { 74 Pop(stack,p); //出棧 75 while (p) 76 { 77 cout<<p->data<<" "; //輸出當前指向結點 78 if(p->rchild)Push(stack,p->rchild); //訪問右指點 79 p=p->lchild; 80 } 81 } 82 cout<<endl; 83 } 84 //後序非遞歸遍歷 85 void PostOrder(BiTree T) 86 { 87 BiTree stack[MaxSize],p; 88 int top=0; 89 p=T; 90 do 91 { 92 while (p!=NULL) 93 { 94 stack[++top]=p; 95 p=p->lchild; 96 } 97 while (top>0&&stack[top]->rchild==p) 98 { 99 p=stack[top--]; //棧頂結點出棧 100 cout<<p->data<<" "; //訪問p所指向的結點 101 } 102 if (top>0) 103 p=stack[top]->rchild; //開始遍歷右子樹 104 105 }while(top>0); 106 cout<<endl; 107 }
二叉樹的基本操做已經總結完了,下面是一些補充:
1 //計算葉子結點的個數 2 void CountLeaf(BiTree T,int &count) 3 { 4 5 if(T) 6 { 7 if((!T->lchild)&&(!T->rchild)) 8 count++; 9 CountLeaf(T->lchild,count); //左子樹葉子個數 10 CountLeaf(T->rchild,count); //右子樹葉子個數 11 } 12 }//CountLeaf 13 //計算雙結點個數 14 void CountParent(BiTree T,int &count) 15 { 16 if(T) 17 { 18 if(T->lchild&&T->rchild) 19 count++; 20 CountParent(T->lchild,count); //左子樹雙結點個數 21 CountParent(T->rchild,count); //右子樹雙結點個數 22 } 23 } 24 //計算二叉樹結點個數 25 void Count(BiTree T,int &count) 26 { 27 if(T) 28 { 29 Count(T->lchild,count); 30 Count(T->rchild,count); 31 count++; //結點個數 32 } 33 34 } 35 //單結點個數 36 void CountChild(BiTree T,int &count) 37 { 38 if(T) 39 { 40 if((T->lchild&&(!T->rchild))||(T->rchild&&(!T->lchild))) 41 count++; 42 CountChild(T->lchild,count); //左子樹單結點個數 43 CountChild(T->rchild,count); //右子樹單結點個數 44 } 45 } 46 //計算樹的高度 47 int Depth(BiTree T) 48 { int depthval,depthLeft,depthRight; 49 if(!T) depthval=0; 50 else 51 {depthLeft=Depth(T->lchild); //左子樹高度 52 depthRight=Depth(T->rchild); //右子樹高度 53 depthval=1+(depthLeft>depthRight ?depthLeft:depthRight); //取高度最高 54 } 55 return depthval; //返回 56 } 57 //計算任意結點所在的層次 58 int NodeLevel(BiTree T,TElemType &p,int &count) 59 { 60 if(T==NULL) 61 return 0; 62 if(T->data==p) 63 return 1; 64 if(NodeLevel(T->lchild,p,count)||(NodeLevel(T->rchild,p,count))) 65 { 66 count++; 67 return 1; 68 } 69 // return 0; 70 71 } 72 //交換二叉樹左右子樹 73 void Exchange(BiTree &T) 74 { 75 76 BiTree temp; 77 if (T == NULL) 78 return; 79 Exchange(T ->lchild); //交換左子樹 80 Exchange(T ->rchild); //交換右子樹 81 temp = NULL; 82 temp = T ->lchild; //交換 83 T->lchild=T->rchild; 84 T->rchild=temp; 85 86 } 87 //判斷兩樹是否類似 88 int LikeBiTree(BiTree T1,BiTree T2) 89 { 90 int like1,like2; 91 if(T1==NULL&&T2==NULL) 92 return 1; 93 else if(T1==NULL||T2==NULL) 94 return 0; 95 else 96 { 97 like1=LikeBiTree(T1->lchild,T2->lchild); 98 like2=LikeBiTree(T1->rchild,T2->rchild); 99 return(like1&&like2); 100 } 101 102 }//LikeBiTree
層次遍歷二叉樹(隊列實現)
1 /* 2 二叉樹的層次遍歷 3 input: 4 2 5 10 5 4 -1 -1 -1 20 19 -1 -1 40 -1 -1 6 30 10 8 20 -1 -1 -1 -1 50 40 -1 45 -1 -1 -1 7 output: 8 10 5 20 4 19 40 9 30 10 50 8 40 20 45 10 */ 11 #include<iostream> 12 #include<queue> 13 using namespace std; 14 struct BTreeNode{ 15 //二叉樹 16 int data; 17 BTreeNode *lchild; 18 BTreeNode *rchild; 19 }; 20 void LayerOrder(BTreeNode *t){ 21 //利用隊列實現層次遍歷,每次訪問根結點,而後一次放入左結點和右結點(若是有的話)。 22 if(t == NULL)return ; 23 queue<BTreeNode*> q; 24 BTreeNode *temp; 25 q.push(t); 26 while(!q.empty()){ 27 temp = q.front(); 28 q.pop(); 29 cout<<temp->data<<' '; 30 if(temp->lchild != NULL)q.push(temp->lchild); 31 if(temp->rchild != NULL)q.push(temp->rchild); 32 } 33 } 34 void Create(BTreeNode *&t){ 35 //(測試用)以先序遍歷構建二叉樹 36 int x; 37 cin>>x; 38 if(x == -1) 39 t = NULL; 40 else 41 { 42 t = new BTreeNode; 43 t->data = x; 44 Create(t->lchild); 45 Create(t->rchild); 46 } 47 } 48 int main(){ 49 BTreeNode *root = NULL; 50 int t; 51 cin>>t; 52 while(t--) 53 { 54 Create(root); 55 LayerOrder(root); 56 cout<<endl; 57 } 58 return 0; 59 }
基礎篇講完啦~~~快下課了(上機課已經無聊到寫博客了==造福人類吖*。*)