C語言數據結構(11)--使用鏈表描述子節點的普通樹實現

數組描述子節點的缺點

如果有這麼一顆奇葩的樹,大多數節點的孩子數爲1-2個,但是有一個節點的孩子數是100個。

因爲我們使用數組描述子節點,所以描述子節點的數組得定義爲struct TreeNode* children[100];

也就是說,除了有一個充分利用了數組分配的空間,其他的都造成了極大浪費,毫無疑問不合理。

使用鏈表描述

孩子也是一個一維的集合,特點個數不確定,符合這種特點的數據結構就是鏈式線性表了(簡稱鏈表)。

我們再來仔細觀察下樹的結構圖,來嘗試定義節點的數據結構:

圖片描述

  1. 首先一個節點得有一個數據區域,保存節點的數據信息,最簡單就是保存一個int數據。
  2. 每個節點有多個孩子,這個可以使用一個鏈表來描述,因爲鏈表指定了頭指針,就能把整個鏈表帶出來,所以可以定義節點爲。
typedef struct {
	int data;//數據區域
	TreeNode* node;//保存孩子中的頭結點
}TreeNode;

上面的節點數據結構乍一看沒啥問題,對於節點1來說,data區域保存1,node的data保存2,node的node指向3。

但是2下面的5和6呢,已經沒有地方存儲了。

我們再次仔細分析下節點,實際上每個節點除了要通過一個鏈表保存兄弟節點,還需要一個鏈表保存孩子節點。

於是結構應該爲:

typedef struct {
	int data;//數據區域
	TreeNode* brother;//保存兄弟節點 如果爲NULL表示無
	TreeNode* son;//保存孩子節點 如果爲NULL表示無
}TreeNode;

也就是說,我們的存儲結構實際上是,同樣能表達含義一模一樣的樹。

圖片描述

代碼實現

嗯,這個代碼已經有一定理解難度了,我也是寫了大概幾十分鐘才搞定的,C語言真是魅力無窮吭,噴香!

/*
* 使用鏈表描述子節點的普通樹實現
* 作者:熊貓大大
* 時間:2019-10-16
*/
#include <stdio.h>

typedef struct {
	int data;//數據區域
	struct TreeNode* brother;//保存兄弟節點 如果爲NULL表示無
	struct TreeNode* son;//保存孩子節點 如果爲NULL表示無
}TreeNode;

//爲樹的當前節點添加子節點
int addChild(TreeNode* curNode, int data)
{
	//分配新節點
	TreeNode* newNode= (TreeNode*)malloc(sizeof(TreeNode));
	newNode->data = data;
	newNode->brother = NULL;
	newNode->son = NULL;
	//找到當前節點的最後一個字節點
	TreeNode* lastSonNode = curNode->son;//指向第一個子節點
	if (lastSonNode == NULL) //第一個子節點即爲空
	{
		curNode->son = newNode;
		return 1;
	}
	while (lastSonNode->brother != NULL) //找到最後一個節點
	{
		lastSonNode = lastSonNode->brother;
	}
	lastSonNode->brother = newNode;//將新節點掛在最後一個節點後面
	return 1;
}

//遍歷當前節點與子節點
void printTree(TreeNode *node)
{
	printf("父節點:%d",node->data);
	//遍歷打印子節點
	printf("----子節點:");
	TreeNode *p = node->son;
	if (p == NULL) //無子節點
	{
		printf("無\n");
		return 1;
	}
	if (p != NULL) 
	{
		printf("%d ",p->data);
	}
	while(p->brother!=NULL)
	{
		p = p->brother;
		printf("%d ", p->data);
	}
	printf("\n");
	//遍歷遞歸子節點
	TreeNode *q = node->son;
	if (q != NULL)
	{
		printTree(q);
	}
	while (q->brother != NULL)
	{
		q = q->brother;
		printTree(q);
	}
}
//----------------------------------------------------------------------------------------------------測試入口區域
int main()
{
	//設定根節點
	TreeNode root;
	root.data = 1;//根節點數據區域
	root.brother = NULL;//根節點無兄弟節點
	root.son = NULL;//一開始也沒有子節點
	//爲1節點添加2/3/4子節點
	addChild(&root,2);
	addChild(&root, 3);
	addChild(&root, 4);
	//爲2號節點添加5/6子節點
	TreeNode *node2 = root.son;
	addChild(node2, 5);
	addChild(node2, 6);
	//爲3號節點添加7子節點
	TreeNode *node3 = node2->brother;
	addChild(node3, 7);
	//爲4號節點添加8子節點
	TreeNode *node4 = node3->brother;
	addChild(node4, 8);
	printTree(&root);

	return 1;
}

執行結果

毫無疑問,執行結果驗證了代碼的真實性,但是輸出順序稍微有點亂。

主要是因爲現在的輸出是順着一個節點,將其子節點輸出完,才輸出另外節點的邏輯,如果不好理解下個斷點走走就是了。

圖片描述

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