數據結構之樹(附帶二叉樹的存儲及遍歷C語言實現代碼)

樹形結構是一種很重要的非線性存儲結構,其中以樹和二叉樹最爲常見,本篇文章主要講解二叉樹的存儲結構以及各種操作,並研究樹和森林與二叉樹的轉換關係。

1.二叉樹

二叉樹的特點是每個節點至多隻有兩顆字數(即二叉樹不存在度大於2的節點),並且二叉樹的字數有左右之分,次序不能顛倒
二叉樹的性質:

1.在二叉樹的第i層至多有 2n12^{n-1}個節點
2.深度爲k的二叉樹至多有 2k12^{k}-1個節點
3.對於任何一顆二叉樹T,如果其終端節點數爲n0,度爲2的節點數爲n2,則n0=n2+1

二叉樹的遍歷規則:
先序遍歷:先訪問根節點,先序遍歷左子樹,先序遍歷右字數
中序遍歷:中序遍歷左子樹,訪問根節點,中序遍歷右子樹
後續遍歷:後續遍歷左子樹,後續遍歷右子樹,訪問根節點

二叉樹的存儲結構及各種操作代碼:

#include <cstdio>
#include <cstdlib>
#define STACK_INIT_SIZE 100
#define STACKINCREASE 10

typedef char ElemType;

//二叉樹節點定義
typedef struct BiTNode
{
	ElemType data;
	struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;

//創建一顆二叉樹,前序遍歷的方式輸入數據
int CreateBiTree(BiTree *T) 
{
	char c;
	scanf("%c", &c);
	if (' ' == c) {
		*T = NULL;	
	}
	else {
		*T = (BiTNode *)malloc(sizeof(BiTNode));	
		(*T)->data = c;
		CreateBiTree(&(*T)->lchild);
		CreateBiTree(&(*T)->rchild);
	}
	return 0;
}
//打印節點
int visit(char c)
{
	printf("%c ", c);
	return 0;
}

//前序遍歷二叉樹(遞歸實現)
void PreOrderTraverse(BiTree T)
{
	if (T) {
		visit(T->data);
		PreOrderTraverse(T->lchild);
		PreOrderTraverse(T->rchild);
	}
}

//中序遍歷二叉樹(遞歸)
void InOrderTraverse(BiTree T) 
{
	if (T != NULL) {
		InOrderTraverse(T->lchild);
		visit(T->data);
		InOrderTraverse(T->rchild);
	}
}

//後序遍歷二叉樹(遞歸)
void PostOrderTraverse(BiTree T) 
{
	if (T != NULL) {
		PostOrderTraverse(T->lchild);
		PostOrderTraverse(T->rchild);
		visit(T->data);
	}
}

//獲取樹的深度
int GetDepth(BiTree T) 
{
	if(T == NULL) {
		return 0;	
	} else {
		int m = GetDepth(T->lchild);	
		int n = GetDepth(T->rchild);
		if (m > n) {
			return m + 1;	
		}
		else {
			return n + 1;	
		}
	}	
}

//獲取二叉樹的葉子節點數
int CountLeaf(BiTree T, int count) {
	if (T) {
		if (T->lchild == NULL && T->rchild ==NULL) {
			count++;
		}	
		count = CountLeaf(T->lchild, count);
		count = CountLeaf(T->rchild, count);
	}
	return count;
}

//獲取二叉樹的總節點數
int CountNode(BiTree T, int count) {
	if (T) {
		count++;
		count = CountNode(T->lchild, count);
		count = CountNode(T->rchild, count);
	}
	return count;
}

int main(){
	int depth, leafcount = 0, nodecount = 0;
	BiTree T = NULL;
	CreateBiTree(&T);
	PreOrderTraverse(T);
	printf("\n");
	InOrderTraverse(T);
	printf("\n");
	PostOrderTraverse(T);
	printf("\n");
	depth = GetDepth(T);
	printf("%d\n", depth);
	leafcount = CountLeaf(T, leafcount);
	printf("二叉樹葉子數:%d\n", leafcount);
	nodecount = CountNode(T, nodecount);
	printf("二叉樹的節點數:%d\n", nodecount);
	return 0;	
}

2.樹

樹的存儲結構

1.雙親表示法
#define MAX_TREE_SIZE 100
//雙親表示法
typedef int ElemType;
typedef struct PTNode
{
	ElemType data;  //節點數據
	int parent;		//雙親位置	
}PTNode;
typedef struct 
{
	PTNode nodes[MAX_TREE_SIZE];
	int r;  //根的位置
	int n;	//節點數目
}PTree;
2.孩子表示法
#define MAX_TREE_SIZE 100

typedef char ElemType;
//孩子節點
typedef struct CTNode
{
	int child;   //孩子節點的下標
	struct CTNode *next;  //指向下一個孩子節點的指針
}*ChildPtr;

typedef struct 
{
	ElemType data;		
	ChildPtr firstchild; //孩子鏈表頭指針
}CtBox;

typedef struct 
{
	CTBox nodes[MAX_TREE_SIZE];
	int n; //節點數
	int r;//根位置
}
3.孩子兄弟表示法
typedef struct CSNode {
	ElemType data;
	struct CSNode *firstchild, *nextsibling;
}CSNode, *CSTree;

3.二叉樹與樹、森林的轉換

1.二叉樹到樹、森林的轉化

若節點x是其雙親y的左孩子,則把x的右孩子以及右孩子的右孩子。。。,都與y用連線連起來,然後去掉所有雙親到右孩子的連線

2.樹轉化爲二叉樹

在樹中所有兄弟節點之間加一連線,然後對於每個節點,除了保留與其的長子的連線外,去掉該節點與其他孩子的連線

3.森林轉換爲二叉樹

在森林中將所有“兄弟節點”之間加一連線,然後對於每個節點,除了保留與其長子的連線外,去掉該節點與其他孩子的連線

規律
1.判斷一個二叉樹是否是轉換爲二叉樹還是森林,關鍵看這棵二叉樹的根節點是否有右孩子,如果有右孩子則是森林,沒有則是一棵樹
2.樹的遍歷分爲先根遍歷與後根遍歷,森林的遍歷分爲先序遍歷和後序遍歷,樹和森林的前根(序)遍歷和二叉樹的前序遍歷結果相同,樹和森林的後根(序)遍歷與二叉樹的中序遍歷結果相同

4.赫爾曼樹

樹的帶權路徑長度爲樹中所有葉子結點的帶權路徑長度之和,通常記作WPL
WPL最小的二叉樹稱作最優二叉樹或赫爾曼樹

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章