/*
1.節點:節點包含一個數據元素和若干點到其子樹分支
2.度節點:節點的數目已成為節點的子樹
3.葉節點:為0的節點稱為葉結點
4.分支節點:度不為0的節點稱為分支節點
5.樹的度:樹中全部節點的度的最大值
6.二叉樹:是n(n>=0)個有限節點構成的集合。n=0的樹稱為空二叉樹。n=1的樹僅僅有一個根結點;
n〉1的二叉樹由一個根節點和至多兩個互不相交的,分別稱為左子樹和右子樹的子二叉樹構成
二叉樹不是有序樹,這是由於,二叉樹中某個節點即使僅僅有一個子樹也要區分是左子樹還是右子樹;
而對於有序樹來說。假設某個節點僅僅有一個子樹就必然是第一個子樹
7.二叉樹全部結點的形態有5種:空節點,無左右子樹節點,僅僅有左子樹節點。僅僅有右子樹節點和左右子樹均存在的節點
8.滿二叉樹:在一棵二叉樹中。假設全部分支節點都存在左子樹和右子樹,而且全部葉子節點都在同一層,則這種二叉樹稱作滿二叉樹
9.全然二叉樹:假設一顆具有n個節點的二叉樹的結構與滿二叉樹的前n個節點的結構同樣,這種二叉樹稱為全然二叉樹
10二叉樹的性質:
(1):若規定根節點的層數為0,則一棵非空二叉樹的第i層上最多有2^i(i>=0)個節點
(2):
若規定僅僅有根節點的二叉樹的深度為0,則深度為k的二叉樹的最大節點數是2^(k+1)-1(k>=-1)
(3):
對於一棵非空的二叉樹。假設葉節點個數為n0,度為2的節點個數為n2。則有n0=n2+1
(4):
具有n個節點的全然二叉樹的深度k為大於或等於ln(n+1)-1的最小整數
(5):
對於具有n個節點的全然二叉樹,假設依照從上至下和從左至右的順序對全部節點序號從0開始順序編號,則對於序號為i(0<=i<n)的節點有:
假設i〉0。則序號為i節點的雙親節點的序號為(i-1)/2(/為整除);假設i=0。則序號為i節點為根節點,無雙親節點
假設2i+1<n,則序號為i節點的左孩子節點的序號為2i+1;假設2i+1>=n,則序號為i節點無左孩子
假設2i+2<n,則序號為i節點的右孩子節點的序號為2i+2;假設2i+2>=n。則序號為i節點無右孩子
11.二叉樹的存儲結構
1.二叉樹的順序存儲結構
利用性質5,對於全然二叉樹能夠利用一維數組存儲,假設不是全然二叉樹。則能夠補空節點,使成為全然二叉樹在進行存儲,
可是對於非全然二叉樹,可能要浪費非常多的空間。
2.二叉樹的鏈式存儲結構
二叉樹的鏈式存儲結構就是用指針建立二叉樹中節點之間的關系,二叉樹最經常使用的鏈式存儲結構是二叉鏈。二叉樹的二叉鏈存儲結構是一種經常使用的
二叉樹存儲結構。
二叉鏈存存儲結構的長處時。結構簡單。能夠方便的構造不論什么形狀的二叉樹。並能夠方便的實現二叉樹的大多數操作。
二叉鏈存儲結構的缺點是,查找當前節點的雙親節點操作實現比較麻煩
3.二叉樹的仿真指針存儲結構
利用一維數組和結構體實現。利用數組的下標進行仿真指針進行二叉樹的操作
*/
<span style="font-size:18px;">#include<stdio.h> #include<malloc.h> typedef char DataType; typedef struct Node{ DataType data;//數據域 struct Node *leftChild;//左子樹指針 struct Node *rightChild;//右子樹指針 }BiTreeNode;//節點的結構體定義 //初始化 void Initiate(BiTreeNode **root){ *root=(BiTreeNode *)malloc(sizeof(BiTreeNode)); (*root)->leftChild=NULL; (*root)->rightChild=NULL; } //左插入節點 //若當前節點curr非空。則在curr的左子樹插入元素值為x的新節點 //原curr所指節點的左子樹成為新插入節點的左子樹 //若插入成功。則返回新插入節點的指針,否則返回空指針 BiTreeNode *InsertLeftNode(BiTreeNode *curr,DataType x){ BiTreeNode *s,*t; if(curr==NULL){//推斷當前節點是否為空 return NULL;//是空則返回NULL } t=curr->leftChild;//保存原curr所指節點的左子樹 s=(BiTreeNode *)malloc(sizeof(BiTreeNode));//創建節點空間 s->data=x;//賦值 s->leftChild=t;//新插入節點的左子樹為原curr的左子樹 s->rightChild=NULL;//右子樹為空 curr->leftChild=s;//新節點成為curr的左子樹 return curr->leftChild;//返回新插入節點的指針 } //右插入節點 //若當前節點curr非空。則在curr的右子樹插入元素值為x的新節點 //原curr所指節點的右子樹成為新插入節點的右子樹 //若插入成功,則返回新插入節點的指針,否則返回空指針 BiTreeNode *InsertRightNode(BiTreeNode *curr,DataType x){ BiTreeNode *s,*t; if(curr==NULL){//推斷當前節點是否為空 return NULL;//是空則返回NULL } t=curr->rightChild;//保存原curr所指節點的右子樹 s=(BiTreeNode *)malloc(sizeof(BiTreeNode));//創建節點空間 s->data=x;//賦值 s->rightChild=t;//新插入節點的右子樹為原curr的右子樹 s->leftChild=NULL;//右子樹為空 curr->rightChild=s;//新節點成為curr的右子樹 return curr->rightChild;//返回新插入節點的指針 } //左刪除子樹 //若curr非空,則刪除curr所指節點的左子樹 //若刪除成功,則返回刪除節點的雙親節點。否則返回空指針 BiTreeNode *DeleteLeftTree(BiTreeNode *curr){ //假設當前節點為空或者左子樹為空則返回NULL if(curr==NULL||curr->leftChild==NULL){ return NULL; } //釋放節點 //Destroy(&curr->leftChild); curr->leftChild=NULL;//刪除后,當前節點的左子樹為NULL return curr;//返回刪除節點的雙親節點 } //右刪除子樹 //若curr非空。則刪除curr所指節點的右子樹 //若刪除成功,則返回刪除節點的雙親節點,否則返回空指針 BiTreeNode *DeleteRightTree(BiTreeNode *curr){ //假設當前節點為空或者右子樹為空則返回NULL if(curr==NULL||curr->rightChild==NULL){ return NULL; } //釋放節點 // Destroy(&curr->rightChild); curr->rightChild=NULL;//刪除后,當前節點的右子樹為NULL return curr;//返回刪除節點的雙親節點 } void Visit(DataType item){ printf("%c ",item); } //前序遍歷 /* 1.訪問根節點 2.前序遍歷根節點的左子樹 3.前序遍歷根節點的右子樹 */ void PreOrder(BiTreeNode *root,void Visit(DataType item)){ //前序遍歷二叉樹root,訪問操作為Visit()函數 if(root!=NULL){ Visit(root->data);//訪問數據 PreOrder(root->leftChild,Visit);//訪問左子樹 PreOrder(root->rightChild,Visit);//反問右子樹 } } //中序遍歷 /* 1.中序遍歷根節點的左子樹 2.訪問根節點 3.中序遍歷根節點的右子樹 */ void InOrder(BiTreeNode *root,void Visit(DataType item)){ //中序遍歷二叉樹root,訪問操作為Visit()函數 if(root!=NULL){ InOrder(root->leftChild,Visit);//訪問左子樹 Visit(root->data);//訪問數據 InOrder(root->rightChild,Visit);//訪問右子樹 } } //后序遍歷 /* 1.后序遍歷根節點的左子樹 2.后序遍歷根節點的右子樹 3.訪問根節點 */ void PostOrder(BiTreeNode *root,void Visit(DataType item)){ //中序遍歷二叉樹root,訪問操作為Visit()函數 if(root!=NULL){ PostOrder(root->leftChild,Visit);//訪問左子樹 PostOrder(root->rightChild,Visit);//訪問右子樹 Visit(root->data);//訪問根節點數據 } } //撤銷二叉樹操作 void Destroy(BiTreeNode **root){ if((*root)!=NULL&&(*root)->leftChild!=NULL){ Destroy(&(*root)->leftChild); } if((*root)!=NULL&&(*root)->rightChild!=NULL){ Destroy(&(*root)->rightChild); } free(*root); } void PrintBiTree(BiTreeNode *root,int n){ //逆時針旋轉90度。打印二叉樹root。n為縮進層數,初始值為0 int i; if(root==NULL){ return ;//遞歸出口 } PrintBiTree(root->rightChild,n+1);//遍歷打印右子樹 //訪問根節點 for(i=0;i<n-1;i++){ printf(" "); } if(n>0){ printf("---"); printf("%c\n",root->data); } PrintBiTree(root->leftChild,n+1);//遍歷打印右子樹 } //查找數據元素 BiTreeNode *Search(BiTreeNode *root,DataType x){ //查找數據元素x是否在二叉樹root中 //查找到則返回該節點指針。未查找到則返回空指針 BiTreeNode *find=NULL; if(root!=NULL){ if(root->data==x){ find=root; }else{ find=Search(root->leftChild,x);//在左子樹中找 if(find==NULL){ find=Search(root->rightChild,x);//在右子樹中找 } } } return find;//返回查找標志 } void main(){ BiTreeNode *root,*p,*find; char x='E'; Initiate(&root);//初始頭指針 p=InsertLeftNode(root,'A');//在頭結點插入左子樹 p=InsertLeftNode(p,'B');//給'A'插入左子樹 p=InsertLeftNode(p,'D');// p=InsertRightNode(p,'G');// p=InsertRightNode(root->leftChild,'C');//給'A'插入右子樹 InsertLeftNode(p,'E');// InsertRightNode(p,'F');// PrintBiTree(root,0);//旋轉90度打印樹 printf("前序遍歷:"); PreOrder(root->leftChild,Visit); printf("\n中序遍歷:"); InOrder(root->leftChild,Visit); printf("\n后序遍歷:"); PostOrder(root->leftChild,Visit); find=Search(root,x); if(find!=NULL){ printf("\n數據元素%c在二叉樹中\n",x); }else{ printf("\n數據元素%c不在二叉樹中\n",x); } Destroy(&root); }</span>