1. 程式人生 > >二叉樹的基本實現和基本操作

二叉樹的基本實現和基本操作

二叉樹的概念:

一棵二叉樹是結點的一個有限集合,該集合或者為空,或者是由一個根節點加上兩棵分別稱為左子樹和右子樹的二叉樹組成。

二叉樹的特點:

  1. 每個結點最多有兩棵子樹,即二叉樹不存在度大於2的結點
  2. 二叉樹的子樹有左右之分,其子樹的次序不能顛倒

二叉樹的五種形態:

實現程式碼如下:

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

typedef int TDataType;

typedef struct BTreeNode{
	TDataType data;
	struct BTreeNode *left;
	struct BTreeNode *right;
}	BTreeNode;

BTreeNode *CreateNode(int data)
{
	BTreeNode *node = (BTreeNode*)malloc(sizeof(BTreeNode));
	node->data = data;
	node->left = node->right = NULL;

	return node;
}

/*
建立一棵二叉樹
*/
BTreeNode *CreateTree(int preOrder[], int size, int *pUsedSize)
{
	//考慮特殊情況,空
	if (size == 0){
		*pUsedSize = 0;
		return NULL;
	}

	//正常情況
	int leftUsed, rightUsed;
	int rootValue = preOrder[0];
	if (rootValue == -1){
		*pUsedSize = 1;
		return NULL;
	}
	BTreeNode *root = CreateNode(rootValue);

	root->left = CreateTree(preOrder + 1, size - 1, &leftUsed);
	root->right = CreateTree(preOrder + 1 + leftUsed, size - 1 - leftUsed, &rightUsed);
	*pUsedSize = leftUsed + rightUsed + 1;

	return root;
}

/*
遍歷二叉樹
*/

//前序遍歷
void PreOrder(BTreeNode *root)
{
	//考慮空樹
	if (root == NULL){
		return;
	}

	printf(" %d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

//中序遍歷
void InOrder(BTreeNode *root)
{
	if (root == NULL){
		return;
	}

	InOrder(root->left);
	printf(" %d ", root->data);
	InOrder(root->right);
}

//後序遍歷
void PostOrder(BTreeNode *root)
{
	if (root == NULL){
		return;
	}

	PostOrder(root->left);
	PostOrder(root->right);
	printf(" %d ", root->data);
}

/*
求樹的總節點個數
*/
//方法一
int GetSize1(BTreeNode *root)
{
	if (root == NULL){
		return 0;
	}

	int left = GetSize1(root->left);
	int right = GetSize1(root->right);

	return left + right + 1;
}

//方法二
int count = 0;
void GetSize2(BTreeNode *root)
{
	if (root == NULL){
		return;
	}

	GetSize2(root->left);
	GetSize2(root->right);
	count++;
}

/*
求葉子節點個數
*/
int GetLeafSize(BTreeNode *root)
{
	if (root == NULL){
		return 0;
	}

	if (root->left == NULL && root->right == NULL){
		return 1;
	}

	return GetLeafSize(root->left) + GetLeafSize(root->right);
}

//方法二
int num = 0;
void GetLeafSize2(BTreeNode *root)
{
	if (root == NULL){
		return 0;
	}

	if (root->left == NULL && root->right == NULL){
		num++;
	}

	GetLeafSize2(root->left);
	GetLeafSize2(root->right);
}

/*
求第k層的節點個數
*/
int GetLeafKSize(BTreeNode *root,int k)
{
	if (root == NULL){
		//空樹,任意層都是0
		return 0;
	}

	if (k == 1){
		// 第一層只有根節點一個
		return 1;
	}

	int left = GetLeafKSize(root->left, k - 1);
	int right = GetLeafKSize(root->right, k - 1);

	return left + right;
}

/*
求高度/深度
*/ 
#define MAX(a,b)  ( (a)>(b) ? (a):(b) )

int GetHight(BTreeNode *root)
{
	//樹為空
	if (root == NULL){
		return 0;
	}

	//判斷只有一個節點時
	//可寫也可不寫,寫的畫可節省兩次函式呼叫
	if (root == 1){
		return 1;
	}

	return MAX(GetHight(root->left), GetHight(root->right)) + 1;
}

/*
查詢某一節點是否在給定的無重複節點的二叉樹裡
*/
BTreeNode *Find(BTreeNode *root, TDataType data)
{
	if (root == NULL){
		return NULL;
	}

	if (root->data == data){
		return root;
	}

	BTreeNode *result = Find(root->left, data);
	if (result != NULL){
		//左子樹找到了
		return result;
	}

	result = Find(root->right,data);
	if (result != NULL){
		//右子樹找到了
		return result;
	}
	else{
		//沒有找到
		return NULL;
	}
}

測試函式與主函式:

void test()
{
	int preOrder[] = { 1, 2, 3, -1, 4, 5, -1, -1, -1, 6, -1, -1, 7, 8, -1, -1, 9, -1, 0 };
	int size = sizeof (preOrder) / sizeof(int);
	int pUsedSize;
	BTreeNode *root = CreateTree(preOrder, size, &pUsedSize);

	printf("前序遍歷:> ");
	PreOrder(root);
	printf("\n中序遍歷:> ");
	InOrder(root);
	printf("\n後序遍歷:> ");
	PostOrder(root);
	printf("\n");

	printf("節點個數(方法一):> %d\n", GetSize1(root));
	printf("節點個數(方法二):> ");
	GetSize2(root);
	printf("%d\n",count);

	printf("葉子節點個數(方法一):> %d\n", GetLeafSize(root));
	printf("葉子節點個數(方法二):> ");
	GetLeafSize2(root);
	printf("%d\n", num);

	printf("第k層節點個數:> %d\n", GetLeafKSize(root, 4));
	printf("高度:> %d\n", GetHight(root));
	
	if (Find(root, 5) != NULL){
		printf("查詢成功\n");
	}
	else{
		printf("查詢失敗\n");
	}

}
int main()
{
	test();
	return 0;
}

實現效果: