《大話資料結構9》—— “二叉樹的順序儲存結構”——C++程式碼實現
阿新 • • 發佈:2018-11-19
順序儲存結構:
二叉樹的順序儲存結構就是用一維陣列儲存二叉樹中的結點,並且結點的儲存位置,也就是陣列的下標要能體現結點之間的關秀,比如雙親與孩子的關係,左右結點的兄弟關係。
完全二叉樹:
完全二叉樹由於其結構上的特點,通常採用順序儲存方式儲存。一棵有n個結點的完全二叉樹的所有結點從1到n編號,就得到結點的一個線性系列。
如下圖:完全二叉樹除最下面一層外,各層都被結點充滿了,每一層結點的個數恰好是上一層結點個數的2倍,因此通過一個結點的編號就可以推知它的雙親結點及左,右孩子結點的編號:
① 當 2i ≤ n 時,結點 i 的左孩子是 2i,否則結點i沒有左孩子;
② 當 2i+1 ≤ n 時,結點i的右孩子是 2i+1,否則結點i沒有右孩子;
③ 當 i ≠ 1 時,結點i的雙親是結點 i/2;
注意:由於陣列下標從0開始,因此陣列元素的下標等於結點在完全二叉樹中的序號減1。
一般二叉樹:
對於一般的二叉樹,如果仍按照從上至下,從左到右的順序將樹中的結點順序儲存在一維陣列中,則陣列元素下標之間的關係不能夠反映二叉樹中結點之間的邏輯關係。
這時假設將一般二叉樹進行改造,增添一些並不存在的空結點,使之成為一棵完全二叉樹的形式,然後再用一維陣列順序儲存。在二叉樹中假設增添的結點在陣列中所對應的元素值為"空"用^表示。
下面是C++程式碼的示例:
#include<iostream> #include<cassert> using namespace std; using ElementType = int; using Status = void; class FBTree { public: enum State { TT_ERROR = 0, TT_OK = 1 }; public: FBTree(ElementType maxSize); Status treeClear(); ElementType treeCreate(ElementType *array, int length); ElementType treeEmpty(); Status treeDestory(); ElementType treeDepth(); Status treeLen(); ElementType treeRoot( ElementType &rootData); //求樹根的值 ElementType treeValue(int index, ElementType &data); ElementType treeAssign(int index, ElementType value); ElementType treeParent(int index); ElementType treeLeftChild(int index); ElementType treeRightChild(int index); ElementType treeLeftSibling(int index); ElementType treeRightSibling(int index); ElementType treeInsertChild(int index, bool isLeft,int childDepth, int fatherDepth , FBTree insertTree); ElementType treeDeleteChild(int index, bool isLeft); Status preOrderTraverse(); Status levelOrderTraverse(); static int fatherData[]; static int childData[]; private: ElementType *m_base; int m_size;//當前元素的最大容量 int m_len;//當前的元素個數 int m_maxIndex;//按照 完全二叉樹的 排序方法, 所有節點 最大的 索引值,(相當於完全二叉樹 的 節點數) }; int FBTree::fatherData[] = { 1,//第一層 2,3,//第二層 4,5,6,7, 8,0,0,0,0,0,0,0, 16,0,0,0,0, }; int FBTree::childData[]= { 1, 2,3, 0,0,0,0, 0,0,0, }; FBTree::FBTree(ElementType maxSize) { assert(maxSize > 0); m_base = new ElementType[maxSize]; assert(m_base != nullptr); m_len = 0; m_maxIndex = 0; m_size = maxSize; cout << "********************二叉樹的順序儲存結構初始化成功!********************" << "\n" << endl; } Status FBTree::preOrderTraverse() { for (int i = 0; i < m_size; i++) { cout << "第" << i + 1 << "層:"; if (m_base[i] != 0) { cout << "\t" << m_base[i]; } cout << endl; } } Status FBTree::levelOrderTraverse() { int depth = treeDepth(); for (int i = 0; i < depth; i++) { int depthNums =static_cast<int> (pow(2.0, i));//每一層節點數 int startIndex =static_cast<int>(pow(2.0, i)); cout << "第" << i + 1 << "層:"; for (int j = 0; j < depthNums; j++) { int index = startIndex + j; if (index > m_maxIndex) { break; } cout << "\t"<< m_base[index - 1]; } cout << endl; } } ElementType FBTree::treeDeleteChild(int index, bool isLeft) { if (index < 1 || index > m_maxIndex || m_base[index - 1] == 0)//刪除節點不存在 { return TT_ERROR; } int childIndex = isLeft ? (2 * index): (2 * index + 1); //判斷子樹所在的層 int depth = treeDepth(); int childDepth = -1; for (int i = 1; i <= depth; i++) { if (childIndex < pow(2.0, i)) { childDepth = i; break; } } //刪除子樹 for (int i = 0; i <= depth - childDepth; i++) { int startIndex = static_cast <int>(childIndex * pow(2.0, i));//起始座標 for (int j = 0; j < pow(2.0, i); j++) { int deleteIndex = startIndex + j; int data = m_base[deleteIndex - 1]; if (data != 0) { m_len--; m_base[deleteIndex - 1] = 0; } } } //重新尋找 maxIndex int oldSize = m_maxIndex; for (int i = 0; i < oldSize; i++) { int data = m_base[i]; if (data != 0) { m_maxIndex = i + 1; } } return TT_OK; } ElementType FBTree::treeInsertChild(int index, bool isLeft, int childDepth, int fatherDepth, FBTree insertTree) {//插入一個子樹 if (index >= 1 && index <= m_maxIndex && m_base[index - 1] != 0)//父 節點 必須已存在 { int totalDepth = childDepth + fatherDepth;//加入子樹後的深度 int needSize = static_cast <int>(pow(2.0, totalDepth) - 1);//總共需要的 節點數 int childRootIndex = isLeft ? (2 * index) : (2 * index + 1);//子樹 根節點 在 父樹的 索引 if (m_base[childRootIndex - 1] == 0)//子樹不存在,插入子樹.. { for (int i = 0; i < childDepth; i++)//遍歷子樹的每一層 { int childStartIndex = static_cast <int> (pow(2.0, i));//子樹每一層起始座標 int fatherStartIndex = static_cast <int> (childRootIndex * pow(2.0, i)); //父親每一層的起始座標 int total = static_cast <int>(pow(2.0, i)); for (int j = 0; j < total; j++)//每一層幾個.. { int childIndex = childStartIndex + j; if (childIndex > insertTree.m_maxIndex) { break; } int fatherIndex = fatherStartIndex + j; int childData = insertTree.m_base[childIndex - 1]; m_base[fatherIndex - 1] = childData; if (childData != 0) { m_len++; m_maxIndex = m_maxIndex > fatherIndex ? m_maxIndex : fatherIndex; } } } } else//孩子節點已存在 { return TT_ERROR; } } else//父節點不存在 { return TT_ERROR; } return TT_OK; } ElementType FBTree::treeRightSibling(int index) {//若該結點,有右兄弟,返回該結點的右兄弟 int rightIndex = index + 1; if (index <= 1 || rightIndex > m_maxIndex || (index % 2 != 0)) { return TT_ERROR; } ElementType data = m_base[index - 1]; if (data != 0 && m_base[rightIndex - 1] != 0)// 左右節點都存在 { return m_base[rightIndex - 1]; } return TT_ERROR; } ElementType FBTree::treeLeftSibling(int index) {//若該結點,有左兄弟,返回該結點的左兄弟 int leftIndex = index - 1; //根節點 和 第二個節點 都沒有左兄弟,並且 左兄弟的節點 樹 是 2的 倍數 if (index <= 2 || index > m_maxIndex || (leftIndex % 2 != 0)) { return TT_ERROR; } ElementType data = m_base[index - 1]; if (data != 0 && (m_base[leftIndex - 1] != 0))// 左右節點都存在 { return m_base[leftIndex - 1]; } return TT_ERROR; } ElementType FBTree::treeRightChild(int index) {//返回該結點的最右孩子,葉子結點除外 int rChildIndex = 2 * index + 1; if (index < 1 || index > m_maxIndex || rChildIndex > m_maxIndex) { return TT_ERROR; } ElementType data = m_base[index - 1]; if (data != 0 && (m_base[rChildIndex - 1] != 0))// 節點存在,並且孩子節點存在 { return m_base[rChildIndex - 1]; } return TT_ERROR; } ElementType FBTree::treeLeftChild(int index) {//返回該結點的最左孩子,葉子結點除外 int lChildIndex = 2 * index; if (index < 1 || index > m_maxIndex || lChildIndex > m_maxIndex) { return TT_ERROR; } ElementType data = m_base[index - 1]; if (data != 0 && (m_base[lChildIndex - 1] != 0))// 節點存在,並且孩子節點存在 { return m_base[lChildIndex - 1]; } return TT_ERROR; } ElementType FBTree::treeParent(int index) {//返回除樹根之外的某結點的雙親 if (index <= 1 || index > m_maxIndex)//節點超越範圍或者 節點 為根節點 { return TT_ERROR; } ElementType data = m_base[index - 1];// 只要雙親結點存在 if (data != 0)//節點存在 { return (m_base[index / 2 - 1]); } return TT_ERROR; } ElementType FBTree::treeAssign(int index, ElementType value) {//給樹中的某一結點賦值為value if (index < 1 || index > m_maxIndex) { return TT_ERROR; } ElementType oldValue = m_base[index - 1]; //只要該結點存在 if (oldValue != 0) { m_base[index - 1] = value; return TT_OK; } //子樹不存在,賦值失敗 return TT_ERROR; } ElementType FBTree::treeValue(int index, ElementType &data) {//返回樹中某一結點的值 if (index < 1 || index > m_maxIndex) { return TT_ERROR; } data = m_base[index - 1]; return (data != 0 ? TT_OK : TT_ERROR); } ElementType FBTree::treeDepth() { return (m_len == 0 ? 0 : static_cast <int>(log((double)m_maxIndex) / log(2.0) + 1) ); } ElementType FBTree::treeRoot(ElementType &rootData) //求樹根的值 { if (m_len != 0) { rootData = m_base[0]; return TT_OK; } return TT_ERROR; } Status FBTree::treeLen() { cout << "該樹的個數為:" << m_len << endl; } ElementType FBTree::treeEmpty() { return (m_len == 0); } Status FBTree::treeDestory() { this->treeClear(); m_base =nullptr; m_size = 0; if (!m_base && m_size == 0) { cout << "該樹銷燬成功!" << endl; } else { cout << "該樹銷燬失敗!" << endl; } } Status FBTree::treeClear() { delete m_base; m_maxIndex = m_len = 0; if (m_base && (m_maxIndex == 0) && (m_len == 0)) { cout << "該樹已被清空!" << endl; } else { cout << "該樹清空失敗!" << endl; } } ElementType FBTree::treeCreate(ElementType *array, int length) { for (int i = 0; i < length; i++) { ElementType data = array[i]; //每一次迴圈都用data儲存當前的元素 int fatherData = 1; if (i != 0) { fatherData = array[(i + 1) / 2 - 1]; //記錄該結點的雙親 } if (fatherData == 0 && data != 0)//父節點不存在,子節點存在,結構錯誤 { cout << "父節點不存在,子節點存在,結構錯誤" << endl; return TT_ERROR; } m_base[i] = data; // 資料進入陣列 if (data != 0) { m_len++; //元素個數+1 m_maxIndex = i + 1; // 索引值加1 } } return TT_OK; } int main() { int sizeCapacity(0); cout << "輸入順序二叉樹的最大容量:"; cin >> sizeCapacity; FBTree myFBTree(sizeCapacity); myFBTree.treeCreate(FBTree::fatherData, 20); while (true) { { cout << "*************************************************************" << endl << "******************* 順序二叉樹的基本功能展示 *******************" << endl << "*****************************************************************" << endl << "******************** 選擇1——判斷樹是否為空. **********************" << endl << "******************** 選擇2——返回樹的深度. **********************" << endl << "******************** 選擇3——獲取某個結點的雙親. **********************" << endl << "******************** 選擇4——獲取某個結點的左孩子. **********************" << endl << "******************** 選擇5——獲取某個結點的右孩子. **********************" << endl << "*****************************************************************" << endl << "******************** 選擇6——獲取某個結點的左兄弟. **********************" << endl << "******************** 選擇7——獲取某個結點的右兄弟. **********************" << endl << "******************** 選擇8——為樹中某一結點賦值. **********************" << endl << "********************* 選擇9——返回某一結點的值. ************************" << endl << "*****************************************************************" << endl << "********************* 選擇10——返回樹根的值. *****************" << endl << "********************* 選擇11——清空樹. *****************" << endl << "********************* 選擇12——銷燬樹. *****************" << endl << "********************* 選擇13——插入字樹. *****************" << endl << "********************* 選擇14——刪除字樹. *****************" << endl << "******************* 選擇15——清屏! ************************" << endl << "****************** 選擇0——退出程式! ************************" << endl << "***********************************************************************" << endl << "***********************************************************************" << endl; } cout << "\n******************** 請輸入你想要使用的順序表功能的序號 ***************" << endl; cout << "請輸入你的選擇:"; int userChoice(0); cin >> userChoice; if (!userChoice) { cout << "程式已退出,感謝您的使用!" << "\n" << endl; break; } switch (userChoice) { case 1: { if (myFBTree.treeEmpty()) //判斷是否為空 { cout << "目前該順序樹為空!" << endl; myFBTree.treeLen(); } else { cout << "目前順序樹非空!" << endl; myFBTree.treeLen(); myFBTree.levelOrderTraverse(); } break; } case 2: { if (int depht = myFBTree.treeDepth()) { cout << "該樹的深度為:" << depht << endl; myFBTree.treeLen(); } else { cout << "該樹的深度為空!" << endl; } break; } case 3: { cout << "輸入你想獲取哪個結點的雙親:(根結點無雙親!)"; int getParent = 0; cin >> getParent; if (int temp = myFBTree.treeParent(getParent)) { cout << "該結點的雙親為:" << temp << endl; } else { cout << "輸入錯誤,該結點無雙親!" << endl; } break; } case 4: { cout << "輸入你想獲取哪個結點的左孩子:(葉子結點無孩子!)"; int getLetfChild = 0; cin >> getLetfChild; if (int temp = myFBTree.treeLeftChild(getLetfChild)) { cout << "該結點的左孩子為:" << temp << endl; } else { cout << "該結點為葉節點,無左孩子!" << endl; } break; } case 5: { cout << "輸入你想獲取哪個結點的右孩子:(葉子結點無孩子!)"; int getRightChild = 0; cin >> getRightChild; if (int temp = myFBTree.treeRightChild(getRightChild)) { cout << "該結點的右孩子為:" << temp << endl; } else { cout << "該結點為葉節點,無右孩子!" << endl; } break; } case 6: { cout << "輸入你想獲取哪個結點的左兄弟:"; int getLehtBrother = 0; cin >> getLehtBrother; if (int temp = myFBTree.treeLeftSibling(getLehtBrother)) { cout << "該結點的左兄弟為:" << temp << endl; } else { cout << "該結點沒有左兄弟!" << endl; } break; } case 7: { cout << "輸入你想獲取哪個結點的右兄弟:"; int getRightBrother = 0; cin >> getRightBrother; if (int temp = myFBTree.treeRightSibling(getRightBrother)) { cout << "該結點的右兄弟為:" << temp << endl; } else { cout << "該結點沒有右兄弟!" << endl; } break; } case 8: { int overrideData(0); int indexLocition(0); cout << "請輸入你想要賦值的元素位置:"; cin >> indexLocition; cout << "請輸入你想要覆蓋的值為:"; cin >> overrideData; if (myFBTree.treeAssign(indexLocition, overrideData)) { cout << "該結點賦值成功!" << endl; myFBTree.levelOrderTraverse(); } else { cout << "該結點賦值失敗!" << endl; } break; } case 9: { cout << "請輸入你想返回哪個位置的值:"; int temp = 0; int getValue = 0; cin >> getValue; if (myFBTree.treeValue(getValue, temp)) { cout << "該位置的值為:" << temp << endl; } else { cout << "獲取值失敗,該位置沒有值!" << endl; } break; } case 10: { int getRootValue = 0; if (myFBTree.treeRoot(getRootValue)) { cout << "樹根的值為:" << getRootValue << endl; } else { cout << "該樹為空,沒有樹根的值!" << endl; } break; } case 11: { myFBTree.treeClear(); myFBTree.treeLen(); break; } case 12: { cout << "你確定要銷燬該樹嗎?(若銷燬請輸入輸入(Y/y))"; char yesOrNo; cin >> yesOrNo; if ((yesOrNo == 'Y') || (yesOrNo == 'y')) { myFBTree.treeDestory(); } break; } case 13: { int sizeSubCapacity(0); cout << "輸入順序二叉樹的字樹的最大容量:"; cin >> sizeSubCapacity; FBTree childTree(sizeSubCapacity); childTree.treeCreate(FBTree::childData, 10); childTree.levelOrderTraverse(); cout << "請輸入你想在哪個結點上插入一棵字樹:"; int pushDatas = 0; cin >> pushDatas; int childTemp = childTree.treeDepth(); int farentTemp = myFBTree.treeDepth(); myFBTree.treeInsertChild(pushDatas, true, childTemp, farentTemp, childTree); myFBTree.levelOrderTraverse(); break; } case 14: { cout << "請輸入你想刪除的字樹位置:"; int removeSubTree = 0; cin >> removeSubTree; myFBTree.treeDeleteChild(removeSubTree, true); myFBTree.levelOrderTraverse(); break; } case 15: system("cls"); cout << "螢幕已經清屏,可以重新輸入!" << "\n" << endl; break; default: cout << "輸入的序號不正確,請重新輸入!" << "\n" << endl; } } system("pause"); return 0; }