看資料結構寫程式碼(22) 二叉樹的順序儲存方式
阿新 • • 發佈:2019-01-04
二叉樹 是 一個 節點 的度最多是2 ,並且區分 左右子樹的 特殊樹。
二叉樹 有一些特性,這些特性 是 寫 二叉樹順序表的 重要依據,所以先介紹一下:
1.k層的二叉樹,最多有 2 的 k次方 -1 個節點,如果 節點數達到最大值,稱為 滿二叉樹。
2.第k層的二叉樹,最多 有 2的 k-1 次方個節點
3.度為0的節點叫做葉子節點 n0,度為2的節點 n2, no = n2+1
在介紹第4點 之前,先說明一個概念:.完全二叉樹指的是 從 第一層 到 最後一層,從左 到 右,從1 開始 給節點 編號,中間不存在 中斷的節點的 二叉樹。
第4,5點 都是 關於 完全 二叉樹的
4.一個節點數 為n的完全二叉樹的 深度 k為 : k = log2N + 1(log以2為底的N +1,log2N向下取整
5.一個節點數 為n的完全二叉樹,對於任意節點i,
5.1如果 2*i > n則 節點i無左孩子,否則,左孩子為 2*i
5.2 如果 2*i + 1 >n ,則節點 無 右孩子,否則 右孩子 為 2* i+1,
5.3 i==1 時,節點i 是根節點,無雙親,否則 雙親節點 為 i/2 向下取整
下面 開始 說明二叉樹的 順序 儲存方式。
二叉樹的順序儲存方式 ,是按照 完全二叉樹的 順序 將 節點 存放在一個 數組裡,並 將 不存在的節點 設定 為 0.
下面 給出 儲存的 基本形態:
這樣的儲存方式 有 許多的 無用節點 佔據了 儲存空間,造成了 空間的 浪費。所以 這種儲存方式 只適合 完全二叉樹。
下面 給出 我的程式碼:
歡迎指出程式碼不足
執行截圖:// sqBinaryTree.cpp : 二叉樹的順序儲存方式 //特點:只適合完全二叉樹,否則浪費儲存空間巨大 #include "stdafx.h" #include <stdlib.h> #include <math.h> #include <cstring> #define TREE_INIT_SIZE 100 typedef int ElementType; enum E_State { E_State_Error = 0, E_State_Ok = 1, }; //完全二叉樹 struct Tree { ElementType * base; int size;//當前分配的空間大小 int len;// int maxIndex;//按照 完全二叉樹的 排序方法, 所有節點 最大的 索引值,(相當於完全二叉樹 的 節點數) }; E_State treeInit(Tree * t){ //分配記憶體,並且自動清0 t->base = (ElementType *) calloc(TREE_INIT_SIZE,sizeof(ElementType)); if (t->base) { t->size = TREE_INIT_SIZE; t->len = 0; t->maxIndex = 0; return E_State_Ok; } return E_State_Error; } //建立完全二叉樹 E_State treeCreate(Tree * t,ElementType * array,int len){ for (int i = 0; i < len; i++) { ElementType data = array[i]; int fatherData = 1; if (i != 0) { fatherData = array[(i+1)/2 -1]; } if ( fatherData == 0 && data != 0)//父節點不存在,子節點存在,結構錯誤 { printf("父節點不存在,子節點存在,結構錯誤\n"); return E_State_Error; } t->base[i] = data; if (data != 0 ) { t->len ++; t->maxIndex = i + 1; } } return E_State_Ok; } //清空 樹 void treeClear(Tree * t){ for (int i = 0; i < t->size; i++) { t->base[i] = 0; } t->len = 0; t->maxIndex = 0; } //銷燬樹 void treeDestory(Tree * t){ free(t->base); t->base = NULL; t->size = t->len = 0; t->maxIndex = 0; t= NULL; } //下面三個節點 都是 根據 樹 的 長度 來 計算的 bool treeEmpty(Tree t){ return t.len == 0 ? true : false; } int treeLen(Tree t){ return t.len; } //樹的深度 完全二叉樹的 深度 k = log2n + 1 , log2N = In(N) / In(2) int treeDepth(Tree t){ return t.len == 0 ? 0 : log((double)t.maxIndex) / log(2.0) + 1; } //求樹根的值 E_State treeRoot(Tree t,ElementType * rootData){ if (t.len != 0) { *rootData = t.base[0]; return E_State_Ok; } return E_State_Error; } E_State treeValue(Tree t,int index,ElementType * data){ if (index < 1 || index > t.maxIndex) { return E_State_Error; } *data = t.base[index -1]; return *data != 0 ? E_State_Ok : E_State_Error; } E_State treeAssign(Tree * t,int index,ElementType value){ if (t == NULL || index < 1 || index > t->maxIndex) { return E_State_Error; } ElementType oldValue = t->base[index-1]; if (oldValue != 0) { t->base[index-1] = value; return E_State_Ok; } //子樹不存在,賦值失敗 return E_State_Error; } ElementType * treeParent(Tree t,int index){ if (index <= 1 || index > t.maxIndex)//節點超越範圍或者 節點 為根節點 { return NULL; } ElementType data = t.base[index-1]; if (data != 0 )//節點存在 { return t.base + index /2 -1; } return NULL; } ElementType * treeLeftChild(Tree t, int index){ int lChildIndex = 2 * index; if (index < 1 || index > t.maxIndex || lChildIndex > t.maxIndex) { return NULL; } ElementType data = t.base[index-1]; if (data != 0 && t.base[lChildIndex -1] != 0)// 節點存在,並且孩子節點存在 { return t.base + lChildIndex -1; } return NULL; } ElementType * treeRightChild(Tree t,int index){ int rChildIndex = 2 * index + 1; if (index < 1 || index > t.maxIndex || rChildIndex > t.maxIndex ) { return NULL; } ElementType data = t.base[index-1]; if (data != 0 && t.base[rChildIndex -1] != 0)// 節點存在,並且孩子節點存在 { return t.base + rChildIndex -1; } return NULL; } //左兄弟 ElementType * treeLeftSibling(Tree t, int index){ int leftIndex = index -1; //根節點 和 第二個節點 都沒有左兄弟,並且 左兄弟的節點 樹 是 2的 倍數 if (index <= 2 || index > t.maxIndex || leftIndex % 2 != 0) { return NULL; } ElementType data = t.base[index-1]; if (data != 0 && t.base[leftIndex -1] != 0)// 左右節點都存在 { return t.base + leftIndex -1; } return NULL; } //右兄弟 ElementType * treeRightSibling(Tree t,int index){ int rightIndex = index + 1; if (index <= 1 || rightIndex > t.maxIndex || index %2 != 0) { return NULL; } ElementType data = t.base[index-1]; if (data != 0 && t.base[rightIndex -1] != 0)// 左右節點都存在 { return t.base + rightIndex -1; } return NULL; } //插入一個子樹 E_State treeInsertChild(Tree * t,int index,bool isLeft,Tree insertTree){ if (t == NULL) { return E_State_Error; } if(index >= 1 && index <= t->maxIndex && t->base[index-1] != 0)//父 節點 必須已存在 { int childDepth = treeDepth(insertTree); int fatherDepth = treeDepth(*t); int totalDepth = childDepth + fatherDepth;//加入子樹後的深度 int needSize = pow(2.0,totalDepth)-1;//總共需要的 節點數 if (needSize > t->size)//空間不足了 { t->base = (ElementType *)realloc(t->base,needSize); if (t->base ==NULL) { return E_State_Error; } memset(t->base+t->size,0,needSize - t->size -1); t->size = needSize; } int childRootIndex = isLeft ? 2 * index : 2 * index + 1;//子樹 根節點 在 父樹的 索引 if (t->base[childRootIndex -1] == 0)//子樹不存在,插入子樹.. { for (int i = 0; i < childDepth; i++)//遍歷子樹的每一層 { int childStartIndex = pow(2.0,i);//子樹每一層起始座標 int fatherStartIndex = childRootIndex * pow(2.0,i); //父親每一層的起始座標 int total = pow(2.0,i); for (int j = 0; j < total; j++)//每一層幾個.. { int childIndex = childStartIndex + j; if (childIndex > insertTree.maxIndex) { break; } int fatherIndex = fatherStartIndex + j; int childData = insertTree.base[childIndex-1]; t->base[fatherIndex-1] = childData; if (childData != 0) { t->len ++; t->maxIndex = t->maxIndex > fatherIndex ? t->maxIndex : fatherIndex; } } } } else//孩子節點已存在 { return E_State_Error; } } else//父節點不存在 { return E_State_Error; } return E_State_Ok; } //刪除一個子樹,maxIndex 混亂了 E_State treeDeleteChild(Tree * t,int index,bool isLeft){ if (t == NULL) { return E_State_Error; } if (index <1 || index > t->maxIndex || t->base[index-1] == 0)//刪除節點不存在 { return E_State_Error; } int childIndex = isLeft ? 2 * index : 2 * index + 1; //判斷子樹所在的層 int depth = treeDepth(*t); 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 = childIndex * pow(2.0,i);//起始座標 for (int j = 0; j < pow(2.0,i); j++) { int deleteIndex = startIndex +j; int data = t->base[deleteIndex-1]; if (data != 0) { t->len --; t->base[deleteIndex-1] = 0; } } } //重新尋找 maxIndex int oldSize = t->maxIndex; for (int i = 0; i < oldSize; i++) { int data = t->base[i]; if (data != 0) { t->maxIndex = i+1; } } return E_State_Ok; } void preOrderTraverse(Tree t){ for (int i = 0; i < t.size; i++) { if (t.base[i] != 0) { printf("%d : %d\n",i+1, t.base[i]); } } } void inOrderTraverse(Tree t){ } void postOrderTraverse(Tree t){ } void levelOrderTraverse(Tree t){ int depth = treeDepth(t); for (int i = 0; i < depth; i++) { int depthNums = pow(2.0,i);//每一層節點數 int startIndex = pow(2.0,i); printf("第%d層: ",i+1); for (int j = 0; j < depthNums; j++) { int index = startIndex + j; if (index > t.maxIndex) { break; } printf("%d\t",t.base[index-1]); } printf("\n"); } } static int fatherData[] = { 1,//第一層 2,3,//第二層 4,5,6,7, 8,0,0,0,0,0,0,0, 16,0,0,0,0, }; static int childData [] = { 1, 2,3, 0,0,0,0, 0,0,0, }; int _tmain(int argc, _TCHAR* argv[]) { Tree tree1; treeInit(&tree1); treeCreate(&tree1,fatherData,20); levelOrderTraverse(tree1); char * isEmpty = treeEmpty(tree1) ? "是" : "不是"; int depth = treeDepth(tree1); int len = treeLen(tree1); printf("二叉樹是否為空:%s ,長度為 : %d ,深度為 :%d\n",isEmpty,len,depth); ElementType rootData; treeRoot(tree1,&rootData); ElementType * parent = treeParent(tree1,3); if (parent) { printf("節點3 的 父親是 :%d\n",*parent); } else { printf("節點3 無父親 "); } ElementType * leftChild = treeLeftChild(tree1,3); if (leftChild) { printf("節點3 的 左孩子是 :%d\n",*leftChild); } else { printf("節點3無左孩子\n "); } ElementType * rightChild = treeRightChild(tree1,3); if (rightChild) { printf("節點3 的 右孩子是 :%d\n",*rightChild); } else { printf("節點3無右孩子\n "); } ElementType * leftSibling = treeLeftSibling(tree1,3); if (leftChild) { printf("節點3 的 左兄弟是 :%d\n",*leftSibling); } else { printf("節點3無左兄弟\n "); } ElementType * rightSibling = treeRightSibling(tree1,3); if (rightSibling) { printf("節點3 的 右兄弟是 :%d\n",*rightSibling); } else { printf("節點3無右兄弟\n "); } //插入子樹 Tree childTree; treeInit(&childTree); treeCreate(&childTree,childData,10); printf("-------------------子樹------------\n"); levelOrderTraverse(childTree); treeInsertChild(&tree1,7,true,childTree); printf("------在節點7 ,加入 一個 左子樹-----------\n"); levelOrderTraverse(tree1); printf("------------刪除剛才插入的子樹-------------\n"); treeDeleteChild(&tree1,7,true); levelOrderTraverse(tree1); treeDestory(&tree1); treeDestory(&childTree); return 0; }