1. 程式人生 > >看資料結構寫程式碼(22) 二叉樹的順序儲存方式

看資料結構寫程式碼(22) 二叉樹的順序儲存方式

二叉樹 是 一個 節點 的度最多是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;
}
執行截圖: