1. 程式人生 > >【2018.10.10】簡單結構體二叉樹及其應用

【2018.10.10】簡單結構體二叉樹及其應用

簡單結構體二叉樹及其應用

結構體二叉樹的建立可以使用遍歷或者遞迴,各有其特點,遍歷程式碼複雜但是便於理解與閱讀,遞迴理解更復雜,但是對應程式碼量要小很多

1.首先時畫出我們一會要建立的二叉樹。說是樹可我更覺得他像一個根型結構。這個二叉樹在前序遍歷裡的結構是:ABD##E##C#FG.去掉空樹(#)就是ABDECFG.

在這裡插入圖片描述

首先是建立一個結構體,裡面包含左右子節點。以及對應節點的數值。
typedef char Datatype;//這裡我暫時用的char型,因為後面匯入的是字元
typedef struct TNode{
	struct TNode * left;//左子節點
	struct TNode * right;//右子節點
	Datatype data;//節點數值
}TNode; 
接著是對二叉樹建立,也是我自己琢磨最久的一個遞迴,難度在於每次建立二叉樹後,需要返回,你已經使用的節點數,因為不是每個二叉樹都是滿的,存在單子節點。如同建立A的子節點時,我不僅需要得到返回B節點的地址,還需要得到,建立的以B為根時建立下面的樹所消耗的資料個數,為此我們這裡採用一個結構體作為返回值。就很好的解決了問題。
typedef struct{
	TNode * root;//返回建立的節點的地址
	int used;//告訴我,建立節點時消耗的資料個數
}Result;
接著我們開始建立這個二叉樹。顯示節點,然後是遞迴,我會盡量在程式碼裡把註釋寫詳細,但是還需要重複多看。
Result CreateTree(Datatype preorder[], int size)//建立二叉樹,數值採用一個數組裡的值
{
	if (size == 0)//size值為零,說明這是一個空樹。
	{
		Result result = { NULL, 0 };//空樹返回,NULL,使用了0個數據
		return result;
	}
	Datatype rootData = preorder[0];//根節點的賦值,取下陣列的第一個值,賦給根。
	if (rootData == '#')
	{
		Result result = { NULL, 1 };//如果遇見#代表遇到了空樹,返回NULL,但是用了一個數據’‘#,返回1
		return result;
	}
	TNode * root = CreateNode(rootData);//建立一個節點用root接收
	Result leftroot = CreateTree(&preorder[1], size - 1);//對A來說B是左子節點,但是對於D來書,B就是根,我是這麼理解的。所以此處傳陣列第二個數,但是遞歸回去時,就是新的陣列中的第一個資料。
	root->left = leftroot.root;//左樹建立完畢
	Result rightroot = CreateTree(&preorder[1 + leftroot.used], size - 1 - leftroot.used);//同理建立右樹,但是這裡需要減去我們結構體中返回的使用資料的個數。
	root->right = rightroot.root;
	Result result = { root, 1 + leftroot.used + rightroot.used };
	return result;
}
static TNode * CreateNode(Datatype data)//建立節點
{
	TNode *node = (TNode *)malloc(sizeof(TNode));
	node->data = data;
	node->left = NULL;
	node->right = NULL;
	return node;
}
樹就這樣建立完畢裡。接下來我們開始使用。我先把各個功能函式的宣告在這裡寫下來。對照宣告找每個功能函式的定義。

也就是我的標頭檔案。Tree.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include <stdio.h>
typedef char Datatype;//定義資料型別為字元char型
typedef struct TNode{
	struct TNode * left;
	struct TNode * right;
	Datatype data;
}TNode; //建立結構體
typedef struct{
	TNode * root;
	int used;
}Result;//用於對二叉樹建立時返回使用資料的個數,連同節點內容
Result CreateTree(Datatype preorder[], int size);//二叉樹的建立
TNode * CreateNode(Datatype data);//節點的建立
void Preorder(TNode * root);//前序遍歷(遞迴)包括中序遍歷及後續遍歷
int GetNodeSize(TNode *root);//獲得節點個數(遞迴)
int GetLeafNodeSize(TNode *root);//獲得葉子節點個數(遞迴)
int GetNokNodeSize(TNode *root, int k);//獲得第K層節點個數
int GetTreehigh(TNode *root);//獲得樹高
TNode* Search(TNode *root, Datatype key);//搜尋資料
void Mirror(TNode *root);//映象二叉樹(遞迴)
TNode * CommonAncestor(TNode * root, TNode *n1, TNode *n2);//獲取兩個節點的公共祖先節點
int IsbalanceTree(TNode * root);//判斷一個二叉樹是否是平衡二叉樹



void Preorderloop(TNode * root);//前序遍歷非遞迴
void Inorderloop(TNode * root);//中序遍歷非遞迴
void Postorderloop(TNode * root);//後續遍歷非遞迴
void Mirrorloop(TNode * root);//映象二叉樹非遞迴

因為在非遞迴函式中要使用到自定義型別棧這裡加一下自定棧的標頭檔案

Stack.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include <stdio.h>
typedef void * SDatatype;
#define MAX (100)
typedef struct {
	SDatatype arr[MAX];
	int top;//依舊描述大小,棧頂就是大小
}Stack;
void StackInit(Stack *p);
void StackDestroy(Stack *p);
void StackPush(Stack *p, SDatatype data);
void StackPop(Stack *p);
SDatatype StackTop(const Stack *p);
int StackSize(const Stack *p);
int StackEmpty(const Stack *p);

對應的二叉樹函式的定義,我直接放全部Tree.c

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "Tree.h"

Result CreateTree(Datatype preorder[], int size)
{
	if (size == 0)
	{
		Result result = { NULL, 0 };
		return result;
	}
	Datatype rootData = preorder[0];
	if (rootData == '#')
	{
		Result result = { NULL, 1 };
		return result;
	}
	TNode * root = CreateNode(rootData);
	Result leftroot = CreateTree(&preorder[1], size - 1);
	root->left = leftroot.root;
	Result rightroot = CreateTree(&preorder[1 + leftroot.used], size - 1 - leftroot.used);
	root->right = rightroot.root;
	Result result = { root, 1 + leftroot.used + rightroot.used };
	return result;
}
static TNode * CreateNode(Datatype data)
{
	TNode *node = (TNode *)malloc(sizeof(TNode));
	node->data = data;
	node->left = NULL;
	node->right = NULL;
	return node;
}
void Preorder(TNode *root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%c", root->data);
	Preorder(root->left);
	Preorder(root->right);

}
int GetNodeSize(TNode * root)
{
	if (root == NULL)
	{
		return 0;
	}
	return GetNodeSize(root->left) + GetNodeSize(root->right) + 1;
}
int GetLeafNodeSize(TNode *root)
{
	if (root == NULL)
	{
		return 0;
	}
	else
	{
		if (root->left == NULL&&root->right == NULL)
		{
			return 1;
		}
		else
		{
			return GetLeafNodeSize(root->left) + GetLeafNodeSize(root->right);
		}
	}
}
int GetNokNodeSize(TNode *root, int k)
{
	assert(k > 0);
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return GetNokNodeSize(root->left, k - 1) + GetNokNodeSize(root->right, k - 1);
}
int GetTreehigh(TNode *root)
{
	if (root == NULL)
	{
		return 0;
	}
	else
	{
		if (GetTreehigh(root->left) > GetTreehigh(root->right))
		{
			return GetTreehigh(root->left) + 1;
		}
		else
		{
			return GetTreehigh(root->right) + 1;
		}
	}
}
TNode* Search(TNode *root, Datatype key)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->data == key)
	{
		return root;
	}
	TNode * node = Search(root->left, key);
	if (node != NULL)
	{
		return node;
	}
	node = Search(root->right, key);
	if (node != NULL)
	{
		return node;
	}
		return NULL;
}
void Mirror(TNode *root)
{
	if (root == NULL)
	{
		return;
	}
	TNode * node = root->left;
	root->left = root->right;
	root->right = node;
	Mirror(root->left);
	Mirror(root->right);
}
TNode * CommonAncestor(TNode * root, TNode *n1, TNode *n2)
{
	TNode *l1 = Search(root->left, n1->data);
	TNode *l2 = Search(root->left, n2->data);
	if (!l1&&l2)
	{
		return root;
	}
	if (l1&&!l2)
	{
		return root;
	}
	if (l1&&l2)
	{
		return CommonAncestor(root->left, n1, n2);
	}
	else
	{
		return CommonAncestor(root->right, n1, n2);
	}
}
int IsbalanceTree(TNode * root)
{
	if (root == NULL)
	{
		return 1;
	}
	int lb = IsbalanceTree(root->left);
	if (!lb)
	{
		return 0;
	}
	int rb = IsbalanceTree(root->right);
	if (!rb)
	{
		return 0;
	}
	if ((GetTreehigh(root->left) - GetTreehigh(root->right)) >= -1 && (GetTreehigh(root->left) - GetTreehigh(root->right) <= 1))
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

非遞迴二叉樹的函式

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "Tree.h"
#include "Stack.h"

void Preorderloop(TNode * root)
{
	Stack stack;
	StackInit(&stack);
	TNode *node = root;
	TNode *top;
	while (!StackEmpty(&stack)||node != NULL)
	{
		while (node != NULL)
		{
			printf("%c", node->data);
			StackPush(&stack, node);
			node = node->left;
		}
		top = StackTop(&stack);
		StackPop(&stack);
		node = top->right;
	}
}//將printf轉移到top命令下,即為中序遍歷。
void Inorderloop(TNode * root)
{
	Stack stack;
	StackInit(&stack);
	TNode *node = root;
	TNode *top;
	while (!StackEmpty(&stack) || node != NULL)
	{
		while (node != NULL)
		{
			StackPush(&stack, node);
			node = node->left;
		}
		top = StackTop(&stack);
		printf("%c", top->data);
		StackPop(&stack);
		node = top->right;
	}
}
void Postorderloop(TNode * root)
{
	Stack stack;
	StackInit(&stack);
	TNode *node = root;
	TNode *top;
	TNode *last = NULL;
	while (node != NULL || !StackEmpty(&stack))
	{

		while (node != NULL)
		{
			StackPush(&stack, node);
			node = node->left;
		}
		top = StackTop(&stack);
		if (top->right == NULL || top->right == last)
		{
			printf("%c",top->data);
			last = top;
			StackPop(&stack);
		}
		else
		{
			node = top->right;
		}
	}
}
void Mirrorloop(TNode * root)
{
	Stack stack;
	StackInit(&stack);
	TNode *node = root;
	TNode *top;
	TNode *last = NULL;
	while (node != NULL || !StackEmpty(&stack))
	{

		while (node != NULL)
		{
			StackPush(&stack, node);
			node = node->left;
		}
		top = StackTop(&stack);
		if (top->right == NULL || top->right == last)
		{
			TNode * node = top->left;
			top->left = top->right;
			top->right = node;
			last = top;
			StackPop(&stack);
		}
		else
		{
			node = top->right;
		}
	}
}

測試我們的程式碼

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "Tree.h"

void test()
{
	Datatype preorder[13] = { 'A', 'B', 'D', '#', '#', 'E', '#', '#', 'C', '#', 'F', 'G'};
	int size = sizeof(preorder) / sizeof(Datatype);
	Result rr = CreateTree(preorder,size);
	printf("%d\t%d\n", size, rr.used);
	Preorder(rr.root);
	printf("\n");
	Preorderloop(rr.root);
	printf("\n");
	Inorderloop(rr.root);
	printf("\n");
	Postorderloop(rr.root);
	printf("\n");
	Mirrorloop(rr.root);
	Preorder(rr.root);
	printf("該二叉樹節點個數為:%d\n", GetNodeSize(rr.root));
	printf("該二叉樹葉子節點個數為:%d\n", GetLeafNodeSize(rr.root));
	int k = 3;
	printf("該二叉樹第%d層的節點個數為:%d\n",k,GetNokNodeSize(rr.root,k));
	printf("該二叉樹的高度為%d\n", GetTreehigh(rr.root));
	TNode *node = Search(rr.root, 'A');
	if (node == NULL)
	{
		printf("沒找到\n");
	}
	else
	{
		printf("查詢內容的地址為:%p\n", node);
	}
	if (IsbalanceTree(rr.root))
	{
		printf("平衡二叉樹");
	}
	else
	{
		printf("非平衡二叉樹");
	}
}
int main()       
{
	test();
}

在這裡插入圖片描述

這是我對結構體簡單二叉樹的部分總結。望各位大佬指正。