資料結構樹之二叉樹
二叉樹的定義:
是一顆空樹或者具有以下性質
1.結點最多隻有兩個孩子,且有左右之分。不能交換左右孩子
2.結點點的左子樹和右子樹也是二叉樹。
例圖
二叉樹的基本形態:
二叉樹中的術語:
1).結點度:節點所擁有的字數的個數成為該節點的度,在二叉樹中度的取值只能是0,1,2.
2).葉節點:度為0的節點成為葉結點或終端結點。
3).左孩子、右孩子、雙親:樹中一個結點的子樹的根結點稱為這個結點的孩子。這個結點稱為它孩子結點的雙親。具有同一個雙親的孩子結點互稱為兄弟。
4).路徑、路徑長度:如果一棵樹的一串結點n1,n2,…,nk有如下關係:結點ni是ni+1的父結點(1≤i<k),就把n1,n2,…,nk稱為一條由n1至nk的路徑。這條路徑的長度是k-1。
5).結點的層數:規定樹的根結點的層數為1,其餘結點的層數等於它的雙親結點的層數加1。
6).樹的深度:樹中所有結點的最大層數稱為樹的深度。
7).滿二叉樹。 在一棵二叉樹中,如果所有分支結點都存在左子樹和右子樹,並且所有葉子結點都在同一層上,這樣的一棵二叉樹稱作滿二叉樹。
8).完全二叉樹。一棵深度為k的有n個結點的二叉樹,對樹中的結點按從上至下、從左到右的順序進行編號,如果編號為i(1≤i≤n)的結點與滿二叉樹中編號為 i的結點在二叉樹中的位置相同,則這棵二叉樹稱為完全二叉樹。完全二叉樹的特點是:葉子結點只能出現在最下層和次下層,且最下層的葉子結點集中在樹的左 部。
二叉樹的性質:
1).非空二叉樹葉子結點數等於度為2的結點數加1,即N0=N2+1.(其中N0和N2分別是葉結點和度為2結點的個數)。
2).非空二叉樹第K層上最多有 2^(k - 1)個結點(K>= 1).
3).高度為H的節點,最多有2^H - 1個節點(H >= 1).
二叉樹的基本操作:
/*以下為二叉樹的常用操作(如有錯誤之處還望之處)
採用二叉連結串列的儲存結構*/
1 typedef struct BiTNode //二叉樹的節點 2 { 3 DataType m_Value; 4 BiTNode *m_pLeft;5 BiTNode *m_pRight; 6 }BiTNode;
//建立二叉樹(先序)
1 //建立二叉樹(先序) 2 void createBiTree(BiTNode * &pCurrent) 3 { 4 cout << "先序輸入節點:"; 5 DataType value; 6 cin >> value ; 7 if(value == '#') 8 pCurrent = NULL; 9 else 10 { 11 pCurrent = (BiTNode *)malloc(sizeof(BiTNode)); 12 pCurrent->m_Value = value; 13 createBiTree(pCurrent->m_pLeft); 14 createBiTree(pCurrent->m_pRight); 15 } 16 }
//遞迴實現前序遍歷二叉樹
1 void preOrderVisitUseRecur(const BiTNode * pCurrent) 2 { 3 if(pCurrent) 4 { 5 cout << pCurrent->m_Value << " "; 6 preOrderVisitUseRecur(pCurrent->m_pLeft); 7 preOrderVisitUseRecur(pCurrent->m_pRight); 8 } 9 }
//用棧,不用遞迴實現前序排列
1 void preOrderVisitUseStack(const BiTNode * pCurrent) 2 { 3 stack<const BiTNode *> pNodeStack; 4 const BiTNode *p = pCurrent; 5 while(p||!pNodeStack.empty()) 6 { 7 if(p) //如果該節點不是NULL 8 { 9 cout << pCurrent->m_Value << " "; //訪問節點的值 10 pNodeStack.push(p); //將節點壓棧 11 p = p->m_pLeft; 12 } 13 else 14 { 15 //如果該節點是NULL 16 p = pNodeStack.top(); //獲取棧頂元素 17 pNodeStack.pop(); //刪除棧頂元素 18 p = p->m_pRight; //訪問右節點 19 } 20 21 } 22 }
//遞迴實現中序遍歷
1 void inOrderVisitUseRecur(const BiTNode * pCurrent) 2 { 3 if(pCurrent) 4 { 5 inOrderVisitUseRecur(pCurrent->m_pLeft); 6 cout << pCurrent->m_Value << " "; 7 inOrderVisitUseRecur(pCurrent->m_pRight); 8 } 9 }
//用棧實現中序遍歷
1 void inOrderVisitUseStack(const BiTNode * pCurrent) 2 { 3 stack<const BiTNode *> pNodeStack; 4 const BiTNode * p = pCurrent; 5 while(p||!pNodeStack.empty()) 6 { 7 if(p) //如果該節點不是NULL 8 { 9 pNodeStack.push(p); //將節點壓棧 10 p = p->m_pLeft; 11 } 12 else 13 { 14 //如果該節點是NULL 15 p = pNodeStack.top(); //獲取棧頂元素 16 pNodeStack.pop(); //刪除棧頂元素 17 cout << pCurrent->m_Value << " "; //訪問節點的值 18 p = p->m_pRight; //訪問右節點 19 } 20 } 21 }
//遞迴實現後序遍歷
1 void afterOrderVisitUseRecur(const BiTNode * pCurrent) 2 { 3 if(pCurrent) 4 { 5 afterOrderVisitUseRecur(pCurrent->m_pLeft); 6 afterOrderVisitUseRecur(pCurrent->m_pRight); 7 cout << pCurrent->m_Value << " "; 8 } 9 }
//用棧實現後序遍歷
1 void afterOrderVisitUseStack(const BiTNode * pCurrent) 2 { 3 stack<const BiTNode *> pNodeStack1; 4 stack<const BiTNode *> pNodeStack2; 5 const BiTNode * p =pCurrent; 6 while(p||!pNodeStack1.empty()) 7 { 8 if(p) //如果該節點不是NULL 9 { 10 pNodeStack1.push(p); //將節點壓棧 11 pNodeStack2.push(p); //將節點壓棧 12 p = p->m_pRight; 13 } 14 else 15 { 16 //如果該節點是NULL 17 p = pNodeStack1.top(); //獲取棧頂元素 18 pNodeStack1.pop(); //刪除棧頂元素 19 p = p->m_pLeft; //訪問左節點 20 } 21 } 22 p = NULL; 23 while(!pNodeStack2.empty()) 24 { 25 p = pNodeStack2.top(); //獲取棧頂元素 26 pNodeStack2.pop(); //刪除棧頂元素 27 cout << pCurrent->m_Value << " "; 28 } 29 }
//按層次進行遍歷(有點小問題)
1 /* 2 void levelOrderVisit(const BiTNode *pCurrent) 3 { 4 deque<const BiTNode *> pNodedeue; 5 const BiTNode * p = NULL; 6 if(pCurrent) 7 { 8 pNodedeue.push_back(pCurrent); //第一次將節點放到佇列 9 } 10 while(!pNodedeue.empty()||p) 11 { 12 p = *pNodedeue.begin(); //返回佇列首元素,但不刪除 13 pNodedeue.pop_front(); //刪除隊首元素 14 if(p) 15 { 16 cout << p->m_Value; 17 if(p->m_pLeft) 18 pNodedeue.push_back(p); //左孩子不空則進入佇列 19 if(p->m_pRight) 20 pNodedeue.push_back(p); //右孩子不空則進入佇列 21 } 22 } 23 } 24 */
//計算樹的深度
1 int getTreeDepth(const BiTNode * pCurrent) 2 { 3 int leftDepth = 0,rightDepth = 0; 4 if(!pCurrent) 5 { 6 //空的話返回0 7 return 0; 8 } 9 else 10 { 11 leftDepth = getTreeDepth(pCurrent->m_pLeft); //獲得左子樹的高度 12 rightDepth = getTreeDepth(pCurrent->m_pRight); //獲得右子樹的高度 13 return (leftDepth>rightDepth?leftDepth:rightDepth) + 1; 14 } 15 }
//計算樹節點的個數
1 int coutTreeNodeNums(const BiTNode *pCurrent) 2 { 3 int leftNums,rightNums; 4 if(!pCurrent) 5 { 6 return 0; 7 } 8 else 9 { 10 leftNums = coutTreeNodeNums(pCurrent->m_pLeft); 11 rightNums = coutTreeNodeNums(pCurrent->m_pRight); 12 } 13 return leftNums + rightNums + 1; 14 }
//以下是各操作的例項
1 int main() 2 { 3 BiTNode * root = NULL; 4 cout << "start to create a tree:" << endl; 5 createBiTree(root); 6 cout << "visit a tree use 遞迴先序:" << endl; 7 preOrderVisitUseRecur(root); 8 cout << endl; 9 cout << "visit a tree use 棧先序:" << endl; 10 preOrderVisitUseStack(root); 11 cout << endl; 12 cout << "visit a tree use 遞迴中序:" << endl; 13 inOrderVisitUseRecur(root); 14 cout << endl; 15 cout << "visit a tree use 棧中序:" << endl; 16 inOrderVisitUseStack(root); 17 cout << endl; 18 cout << "visit a tree use 遞迴後序:" << endl; 19 afterOrderVisitUseRecur(root); 20 cout << endl; 21 cout << "visit a tree use 棧後序:" << endl; 22 afterOrderVisitUseStack(root); 23 cout << endl; 24 //cout << "層次遍歷:" << endl; 25 //levelOrderVisit(root); 26 cout << "樹中節點的個數:" << coutTreeNodeNums(root) << endl; 27 cout << "樹的深度為:" << getTreeDepth(root) << endl; 28 return 0; 29 }