數據結構入門-樹的遍歷以及二叉樹的創建


樹定義:

  1. 有且只有一個稱為根的節點
  2. 有若干個互不相交的子樹,這些子樹本身也是一個樹

通俗的講:

  1. 樹是有結點和邊組成,
  2. 每個結點只有一個父結點,但可以有多個子節點
  3. 但有一個節點例外,該節點沒有父結點,稱為根節點

一、專業術語

結點、父結點、子結點、根結點

深度:從根節點到最底層結點的層數稱為深度,根節點第一層

葉子結點:沒有子結點的結點

非終端節點:實際上是非葉子結點

度:子結點的個數成為度

二、樹的分類

一般樹:任意一個結點的子結點的個數都不受限制

二叉樹:任意一個結點的子結點個數最多是兩個,且子結點的位置不可更改

二叉數分類:

  1. 一般二叉數
  2. 滿二叉樹:在不增加樹層數的前提下,無法再多添加一個結點的二叉樹
  3. 完全二叉樹:如果只是刪除了滿二叉樹最底層最右邊的連續若干個結點,這樣形成的二叉樹就是完全二叉樹

森林:n個互不相交的樹的集合

三、樹的存儲

二叉樹存儲

連續存儲(完全二叉樹)

優點:查找某個結點的父結點和子結點(也包括判斷有沒有子結點)速度很快

缺點:耗用內存空間過大

鏈式存儲

一般樹存儲

  1. 雙親表示法:求父結點方便

  2. 孩子表示法:求子結點方便

  3. 雙親孩子表示法:求父結點和子結點都很方便

  4. 二叉樹表示法:把一個一般樹轉化成一個二叉樹來存儲,

    • 具體轉換方法:
    • 設法保證任意一個結點的左指針域指向它的第一個孩子,右指針域指向它的兄弟,只要能滿足此條件,就可以把一個一般樹轉化為二叉樹

    一個普通樹轉換成的二叉樹一定沒有右子樹

森林的存儲

先把森林轉化為二叉樹,再存儲二叉樹

四、樹的遍歷

先序遍歷:根左右

先訪問根結點,再先序訪問左子樹,再先序訪問右子樹

先序01.png

先序02.png

中序遍歷:左根右

中序遍歷左子樹,再訪問根結點,再中序遍歷右子樹

中序01.png

中序02.png

后續遍歷:左右根

后續遍歷左子樹,后續遍歷右子樹,再訪問根節點

后序01.png

五、已知兩種遍歷求原始二叉樹

給定了二叉樹的任何一種遍歷序列,都無法唯一確定相應的二叉樹,但是如果知道了二叉樹的中序遍歷序列和任意的另一種遍歷序列,就可以唯一地確定二叉樹

已知先序和中序求后序

先序:ABCDEFGH

中序:BDCEAFHG

求后序: 這個自己畫個圖體會一下就可以了,非常簡單,這里簡單記錄一下

  1. 首先根據先序確定根,上面的A就是根
  2. 中序確定左右,A左邊就是左樹(BDCE),A右邊就是右樹(FHG)
  3. 再根據先序,A左下面就是B,然后根據中序,B左邊沒有,右邊是DCE
  4. 再根據先序,B右下是C,根據中序,c左下邊是D,右下邊是E,所以整個左樹就確定了
  5. 右樹,根據先序,A右下是F,然后根據中序,F的左下沒有,右下是HG,
  6. 根據先序,F右下為G,然后根據中序,H在G的左邊,所以G的左下邊是H

實例01.png

再來一個例子,和上面的思路是一樣的,這里就不詳細的寫了

先序:ABDGHCEFI

中序:GDHBAECIF

實例02.png

已知中序和后序求先序

中序:BDCEAFHG

后序:DECBHGFA

這個和上面的思路是一樣的,只不過是反過來找,后序找根,中序找左右

例子03.png

樹簡單應用

樹是數據庫中數據組織一種重要形式

操作系統子父進程的關系本身就是一棵樹

面向對象語言中類的繼承關系

哈夫曼樹

六、二叉樹的創建

#include <stdio.h>
#include <stdlib.h>

typedef struct Node
{
	char data;
	struct Node * lchild;
	struct Node * rchild;
}BTNode;

/*
二叉樹建立
*/
void BuildBT(BTNode ** tree)
{
	char ch;
	scanf("%c" , &ch); // 輸入數據
	if(ch == '#')  // 如果這個節點的數據是#說明這個結點為空
		*tree = NULL;
	else
	{
		*tree = (BTNode*)malloc(sizeof(BTNode));//申請一個結點的內存
		(*tree)->data = ch; // 將數據寫入到結點里面
		BuildBT(&(*tree)->lchild); // 遞歸建立左子樹
		BuildBT(&(*tree)->rchild); // 遞歸建立右子樹
	}
}

/*
二叉樹銷毀
*/
void DestroyBT(BTNode *tree) // 傳入根結點
{
	if(tree != NULL)
	{
		DestroyBT(tree->lchild);
		DestroyBT(tree->rchild);
		free(tree);  // 釋放內存空間
	}
}

/*
二叉樹的先序遍歷
*/
void Preorder(BTNode * node)
{
	if(node == NULL)
		return;
	else
	{
		printf("%c ",node->data );
		Preorder(node->lchild);
		Preorder(node->rchild);
	}
}

/*
二叉樹的中序遍歷
*/
void Inorder(BTNode * node)
{
	if(node == NULL)
		return;
	else
	{
		
		Inorder(node->lchild);
		printf("%c ",node->data );
		Inorder(node->rchild);
	}
}


/*
二叉樹的后序遍歷
*/
void Postorder(BTNode * node)
{
	if(node == NULL)
		return;
	else
	{
		
		Postorder(node->lchild);
		Postorder(node->rchild);
		printf("%c ",node->data );
	}
}

/*
二叉樹的高度
樹的高度 = max(左子樹高度,右子樹高度) +1
*/
int getHeight(BTNode *node)
{
	int Height = 0;
	if (node == NULL)
		return 0;
	else
	{
		int L_height = getHeight(node->lchild);
		int R_height = getHeight(node->rchild);
		Height = L_height >= R_height ? L_height +1 : R_height +1;
	}

	return Height;
}


int main(int argc, char const *argv[])
{
	BTNode * BTree; // 定義一個二叉樹
	printf("請輸入一顆二叉樹先序序列以#表示空結點:");
	BuildBT(&BTree);

	printf("先序序列:");
	Preorder(BTree);
	printf("\n中序序列:");
	Inorder(BTree);
	printf("\n后序序列:");
	Postorder(BTree);

	printf("\n樹的高度為:%d" , getHeight(BTree));
	return 0;
}
// ABC##DE##F##G##


免責聲明!

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



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