数据结构之二叉树

二叉树的每个结点至多只有两个孩子节点(不存在度大于2的结点),二叉树的孩子节点有左右之分,次序不能颠倒。

头文件:

btree.h

#ifndef __BTREE_H__
#define __BTREE_H__
#include "error.h"


#define BLEFT 0   //表示插入二叉树的左边
#define BRIGHT 1   //表示插入二叉树的右边

typedef char BTreeData;   //事先声明

//二叉树的节点
typedef struct _btreeNode
{
	BTreeData data;
	struct _btreeNode *lchild;  //指向左孩子节点的指针
	struct _btreeNode *rchild;  //指向右孩子节点的指针
}BTreeNode;

//二叉树
typedef struct _btree
{
	BTreeNode *root;            //指向二叉树的根节点
	int count;                 //记录二叉树节点的个数
}BTree;

typedef void (*Print_BTree)(BTreeNode*);

// 创建一棵二叉树
BTree *Create_BTree();

// pos 走的路径 值类似 110(左右右)  011 (右右左)
// count  代表走的步数
// flag   代表被替换的结点应该插入在新节点的位置,如果是BLEFT 表示插在左边,BRIGHT表示插在右边
int Btree_Insert(BTree *tree, BTreeData data, int pos, int count, int flag);

//打印树
void Display (BTree* tree, Print_BTree pfunc);

//删除节点
int Delete (BTree *tree, int pos, int count);

//求树的高度
int BTree_Height (BTree *);

//求树的度
int BTree_Degree (BTree *);

//清空树
int BTree_Clear (BTree *);

//销毁树
int BTree_Destroy (BTree **);

// 前序遍历
void pre_order (BTreeNode *node);

//中序遍历
void mid_order (BTreeNode *node);

//后序遍历
void last_order (BTreeNode *node);



#endif // __BTREE_H__


源文件:

btree.c

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

// 创建一棵二叉树
BTree *Create_BTree()
{
	BTree *btree = (BTree*)malloc(sizeof(BTree)/sizeof(char));
	if (btree == NULL)
	{
		errno = MALLOC_ERROR;
		return NULL;
	}
	btree->count = 0;   //树节点个数为0
	btree->root = NULL;   //根节点指针为空,树为空
	return btree;
}

// pos 走的路径 值类似 110(左右右)  011 (右右左)
// count  代表走的步数
// flag   代表被替换的结点应该插入在新节点的位置,如果是BLEFT 表示插在左边,BRIGHT表示插在右边
int Btree_Insert(BTree *tree, BTreeData data, int pos, int count, int flag)
{
	if (tree == NULL || (flag != BLEFT && flag != BRIGHT))
	{
		return FALSE;
	}
	BTreeNode *node = (BTreeNode*)malloc(sizeof(BTreeNode)/sizeof(char));
	if (node == NULL)
	{
		errno = MALLOC_ERROR;
		return FALSE;
	}
	//初始化节点
	node->data = data;
	node->lchild = NULL;
	node->rchild = NULL;
	
	//找插入的位置
	BTreeNode *parent = NULL;
	BTreeNode *current = tree->root;  //current一开始指向根节点,根节点的父节点是空
	int way;  //保存当前走的位置
	while (count > 0 && current != NULL)
	{
		way = pos & 1;   //取出当前走的方向
		pos = pos >> 1;  //移去走过的路线
		
		//当前位置就是走完以后的位置的父节点
		parent = current;
		
		if (way == BLEFT)  //往左走
		{
			current = current->lchild;
		}
		else               //往右走
		{
			current = current->rchild;
		}
		count--;
	}
	
	//把被替换掉的节点插入到新节点下面
	if (flag == BLEFT)
	{
		node->lchild = current;
	}
	else
	{
		node->rchild = current;
	}
	
	//把新节点插入到二叉树中,way保存了应该插入在父节点的左边还是右边
	if (parent != NULL)
	{
		if(way == BLEFT)
		{
			parent->lchild = node;
		}
		else
		{
			parent->rchild = node;
		}
	}
	else
	{
		tree->root = node;  //替换根节点
	}
	
	tree->count++;
	
	return TRUE;
}

//递归打印
void r_display(BTreeNode* node,Print_BTree pfunc,int gap)
{
	int i;
	if (node == NULL)       //打印空孩子前的“-”
	{
		for(i = 0;i < gap;i++)
		{
			printf ("-");
		}
		printf ("\n");
		return;
	}
	
	for (i = 0;i < gap;i++)
	{
		printf ("-");
	}
	
	//打印节点
	//printf ("%c\n",node->data);
	pfunc (node);
	
	//若是左右孩子都为空,就不打印
	if (node->lchild != NULL || node->rchild != NULL)
	{
		//打印左孩子
		r_display (node->lchild,pfunc,gap+4);
		//打印右孩子
		r_display (node->rchild,pfunc,gap+4);
	}
}

//打印树
void Display (BTree* tree, Print_BTree pfunc)
{
	if (tree == NULL)
	{
		return;
	}
	r_display(tree->root,pfunc,0);
}

//递归删除
void r_delete (BTree *tree,BTreeNode *node)
{
	if (tree == NULL || node == NULL)
	{
		return;
	}
	//先删除左孩子
	r_delete (tree,node->lchild);
	//删除右孩子
	r_delete (tree,node->rchild);
	
	free(node);   //释放掉节点
	tree->count--;
}

//删除节点
int Delete (BTree *tree, int pos, int count)
{
	if (tree == NULL)
	{
		return FALSE;
	}
	
	//找节点
	BTreeNode* parent = NULL;
	BTreeNode* current = tree->root;
	int way;
	while (count > 0 && current != NULL)
	{
		way = pos & 1;
		pos = pos >> 1;
		
		parent = current;
		
		if (way == BLEFT)
		{
			current = current->lchild;
		}
		else
		{
			current = current->rchild;
		}
		count--;
	}
	//将该节点从树上移除
	if (parent != NULL)
	{
		if (way == BLEFT)
		{
			parent->lchild = NULL;
		}
		else
		{
			parent->rchild = NULL;
		}
	}
	else
	{
		tree->root = NULL;  //移除根节点
	}
	
	//释放节点
	r_delete (tree,current);
	
	return TRUE;
}

//递归求树的高度
int r_height (BTreeNode* node)
{
	if (node == NULL)
	{
		return FALSE;
	}
	//求左孩子的高度
	int lh = r_height (node->lchild);
	//求右孩子的高度
	int rh = r_height (node->rchild);
	
	//节点的高度是孩子中最高的高度+1
	return (lh > rh ? lh+1 : rh+1);
}

//求树的高度
int BTree_Height (BTree *tree)
{
	if (tree == NULL)
	{
		return FALSE;
	}
	int ret = r_height(tree->root);
	return ret;
}

//递归求树的度
int r_degree (BTreeNode *node)
{
	if (node == NULL)
	{
		return 0;
	}
	int degree = 0;
	if (node->lchild != NULL)
	{
		degree++;
	}
	if (node->rchild != NULL)
	{
		degree++;
	}
	//度为0代表没有左右孩子,度为2,代表树的度为2
	if (degree == 1)
	{
		int ld = r_degree (node->lchild);
		if (ld == 2)
		{
			return 2;
		}
		int rd = r_degree (node->rchild);
		if (rd == 2)
		{
			return 2;
		}
	}
	return degree;
}

//求树的度
int BTree_Degree (BTree *tree)
{
	if (tree == NULL)
	{
		return FALSE;
	}
	int ret = r_degree(tree->root);
	
	return ret;
}

//清空树
int BTree_Clear (BTree *tree)
{
	if(tree == NULL)
	{
		return FALSE;
	}
	Delete (tree,0,0);  //删除根节点
	
	tree->root = NULL;
	return TRUE;
}

//销毁树
int BTree_Destroy (BTree **tree)  //二级指针
{
	if (tree == NULL)
	{
		return FALSE;
	}
	BTree_Clear (*tree);
	free (*tree);
	*tree = NULL;
	return TRUE;
}

// 前序遍历
void pre_order (BTreeNode *node)
{
	if (node == NULL)
	{
		return;
	}
	printf ("%4c", node->data);  //最先打印根节点
	pre_order (node->lchild);
	pre_order (node->rchild);
}

//中序遍历
void mid_order (BTreeNode *node)
{
	if (node == NULL)
	{
		return;
	}
	mid_order (node->lchild);
	printf ("%4c", node->data);    //中间打印根节点
	mid_order (node->rchild);
}

//后序遍历
void last_order (BTreeNode *node)
{
	if (node == NULL)
	{
		return;
	}
	last_order (node->lchild);	
	last_order (node->rchild);
	printf ("%4c", node->data);     //最后打印根节点
}




关于二叉树的更多的操作,比如非递归实现二叉树遍历,可以大家一起去实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值