數據結構:樹和森林


樹是數據結構內很重要的一種結構。不過我們此處不深究,僅討論二叉樹,線索二叉樹,哈夫曼樹(最優樹)。

二叉樹

定義:(1)空樹;(2)只有一個根節點;(3)有左右兩個子樹,並且子樹也是一顆二叉樹(如圖)。在這里插入圖片描述


性質:
1.第 i 層上最多有 2 i 1 2^{i-1} 個節點.

2.深度為k的樹最多有 2 k 2^k -1個節點,我們稱之為滿二叉樹,滿二叉樹在底層從右向左減少n個節點,此時稱為完全二叉樹。

3.度為0的結點的個數為度為2的節點個數加一, n 0 = n 2 + 1 n_0=n_2+1 .

4.n個節點的完全二叉樹的深度為[ l o g 2 n log_2n ]+1。注釋:[x]表示不超過x的最大整數,也就是向下取整。

5.節點序號為 i ,在子節點存在的情況下,節點的序號為2i和2i+1


遍歷方式
1.先序遍歷:先訪問根節點,再訪問左子樹然后是右子樹。
2.中序遍歷:先訪問左子樹,再訪問根節點然后再右子樹。
3.后序遍歷:先訪問左子樹,再訪問右子樹然后是根節點。
先序中序,后序中序能唯一的確定唯一一個二叉樹
還有其他三種遍歷方式 : 只需將以上三種方式的左和右換位置即可


存儲結構
1.順序存儲結構(由於太浪費內存,所以說一般不用)

2.鏈式存儲結構:利用二叉鏈表來組成的二叉樹(有n個節點的二叉樹,含有n+1個空鏈域)。

#include<stdio.h>

typedef struct Lnode{
	char data;
	struct Lnode *left,*right;
}Lnode,*linkLnode;

//創建樹
void setleaf(linkLnode &L){
	char data;
	scanf("%c",&data);

	if(data=='#'){
		L=NULL;
		return;
	}
	
	Lnode *w=new Lnode;
	L=w;
	L->data=data;
	setleaf(L->left);
	
	setleaf(L->right);
}

//先序遍歷
void xian(linkLnode L){
	
	
	if(L==NULL)
		return;
	else
		printf("%c\t",L->data);
	
	xian(L->left);
	xian(L->right);

}
//中序遍歷
void zhong(linkLnode L){

	if(L==NULL)
		return;

	zhong(L->left);
	printf("%c\t",L->data);
	zhong(L->right);

}
//后序遍歷
void hou(linkLnode L){

	if(L==NULL)
		return;
	hou(L->left);

	hou(L->right);
	printf("%c\t",L->data);
}

//度為0的節點個數
int ling(linkLnode L){
	int i;
	if(L!=NULL)
		i=ling(L->left)+ling(L->right);
	else
		return 0;
	
	if(L->left==NULL && L->right==NULL)
		i=i+1;
	return i;
}

//度為1的節點個數
int yi(linkLnode L){
	int i;
	if(L!=NULL)
		i=yi(L->left)+yi(L->right);
	else
		return 0;
	
	if((L->left==NULL && L->right!=NULL) ||(L->left!=NULL && L->right==NULL))
		i=i+1;
	return i;
}

//從數的最左邊,最底層,開始往高處,往右側檢測
//度為2的節點個數
int er(linkLnode L){
	int i;
	if(L!=NULL)
		i=er(L->left)+er(L->right);
	else
		return 0;
	
	if(L->left!=NULL && L->right!=NULL)
		i=i+1;
	return i;
}




//計算樹的深度
int deep(linkLnode L){
	
	if(L==NULL)
		return 0;

	if( deep(L->left) > deep(L->right) )
		return deep(L->left)+1;
	else
		return deep(L->right)+1;

}


void main(){
	linkLnode L;
	L=new Lnode;
	L->left=L->right=NULL;

	
	printf("請以先序遍歷的方式輸入(#代表此位置無值)\n");
	setleaf(L);
	printf("創建成功\n");


	printf("先序遍歷:\n");
	xian(L);

	printf("\n中序遍歷:\n");

	zhong(L);

	printf("\n后序遍歷:\n");
	hou(L);


	printf("\n度為0的節點個數為:%d\n",ling(L));
	printf("\n度為1的節點個數為:%d\n",yi(L));
	printf("\n度為2的節點個數為:%d\n",er(L));

	printf("\n樹的深度為:%d\n",deep(L));
}


線索二叉樹

線索二叉樹與二叉樹大致一樣,只不過是將空鏈域充分利用起來,便於查找每個節點的前驅和后繼。
代碼僅是中序線索二叉樹

#include<stdio.h>

typedef struct Lnode{
	char data;
	struct Lnode *left,*right;
	int zuo,you;
}Lnode,*linkLnode;


//創建樹
void setleaf(linkLnode &L){
	char data;
	scanf("%c",&data);

	if(data=='#'){
		L=NULL;
		return;
	}
	
	Lnode *w=new Lnode;
	L=w;
	L->data=data;
	setleaf(L->left);
	
	setleaf(L->right);
}

//中序遍歷
void zhong(linkLnode &L){
	
	if(L==NULL)
		return;
	
	zhong(L->left);
	zhong(L->right);

	if(L->left==NULL)
		L->zuo=0;
	else
		L->zuo=1;

	if(L->right==NULL)
		L->you=0;
	else
		L->you=1;
}
//設置線索
void guo(linkLnode &L){
	
	Lnode *m,*n;
	m=L->left;n=L->right;
	printf("此時進入到了%c\n",L->data);		//輸出一些過程,便於觀察
	if(L->zuo!=0){
		while(m->you==1)
			m=m->right;
		
		m->right=L;
		printf("m的指向值為%c,m的右側為%c\n",m->data,m->right->data);
		guo(L->left);
	}
	printf("此時返回到了%c\n",L->data);

	if(L->you!=0){
		while(n->zuo==1)
			n=n->left;
		
		n->left=L;
		printf("n的指向值為%c,n的左側為%c\n",n->data,n->left->data);
		guo(L->right);
	}

	printf("准備返回上一層\n");
	return;

}



void zhongappear(linkLnode L){
	Lnode *m;
	m=L;

	while(1){
		
		while(m->zuo==1)
			m=m->left;
		if(m==NULL)
			break;
		printf("%c\t",m->data);
		
		if(m->you==0){
			printf("%c\t",m->right->data);
			m=m->right->right;}
		else
			m=m->right;
		if(m==NULL){
			printf("圓滿結束\n");
			break;}
		
	}
}

void main(){

	linkLnode L,S;
	L=new Lnode;
	S=new Lnode;
	S->you=0;S->zuo=1;
	S->left=L;
	L->left=L->right=NULL;

	printf("請以先序遍歷的方式輸入(#代表此位置無值)\n");
	setleaf(L);
	printf("創建成功\n");

	zhong(L);
	guo(L);

	printf("\n中序遍歷結果:\n");
	zhongappear(L);


}


哈夫曼樹

又名最優樹,就是指帶權路徑最小的數,也是二叉樹的一種,僅包含度為0或者2的節點。

構造方法
取權值最小的兩個節點,作為額外一個空節點的左右兩個孩子,然后取第三小的權值節點,與這顆樹組成新樹,以此類推,構成一顆哈夫曼樹。權值越大的節點離根節點越近。

在這里插入圖片描述




森林

一棵樹為樹,兩棵樹及以上則稱為森林

前面介紹的僅是二叉樹,一個節點只能有兩個孩子,對於樹的話則是一個節點可以有無數個孩子

存儲結構
1.雙親表示法:節點存儲在線性表中,每個節點除了存數data外,還存儲父親的下標,這種方法查找節點的父親很容易,查找孩子的話則不簡便。

2.孩子表示法:用的是一個順序表,然后鏈接許多鏈表構成分,連表內包含的是其孩子。

3.孩子兄弟表示法:此方法等於說是將樹化為一顆二叉樹,孩子在左,兄弟在右,處理方法將於二叉樹類似了,頗為常用(根節點的右孩子必為空)。

遍歷
1.先根遍歷:等於二叉樹的前序遍歷,應為根節點的右孩子為空。
2.后根遍歷:等於二叉樹的中序遍歷



森林

兩顆及以上的樹構成森林,森林也可以轉化為一棵樹,規則也是孩子在左,兄弟在右

遍歷
1.先序遍歷:等於二叉樹的先序
2.中序遍歷:等於二叉樹的中序


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM