数据结构:二叉树

一、树

一种非线性的数据结构,树的结点包含一个数据及若干指向子树的分支。
结点拥有的子树数称为结点的度。度为0的结点称为叶结点,度不为0的结点称为分支结点。
树的度定义为所有结点中度的最大值。
树中结点的最大层次称为树的高度或深度。

在这里插入图片描述

二、二叉树

一个根结点上最多有两个结点的树称为二叉树。

满二叉树:二叉树中所有分支结点的度数都为2,且叶结点都在同一层次上。
完全二叉树:如果一棵具有n个结点的高度为k的二叉树,它每一个结点都与高度为k的满二叉树中编号为1-n的结点一一对应,则这棵二叉树称为完全二叉树。

同样结点数的二叉树,完全二叉树的高度最小。

主要性质
1.在二叉树的第 i 层最多有 2^(i-1) 个结点。

2.深度为k 的二叉树最多有(2^k ) - 1 个结点

3.对于任何的一棵二叉树,如果其叶结点有n0个,度为2的非叶结点有n2个,则 n0 = n2 + 1。===>n1+2n2 = n0+n1+n2-1

4.具有n 个结点的完全二叉树的高度为log2n +1

5.编号从0开始,左孩子结点的编号为2n+1,右孩子结点的编号为2n+2
编号从1开始,左孩子结点的编号为2n, 右孩子结点的编号为2n+1

BTree.h文件

#ifndef _BTREE_H_
#define _BTREE_H_

typedef enum{FALSE, TRUE}  BOOL;
typedef enum{LEFT, RIGHT}  MOUNTWAY;//挂载

typedef char  BTreeData;

typedef struct btreeNode        // 二叉树的结点
{
	BTreeData data;             // 数据
	struct btreeNode *lchild;   // 左孩子结点指针
	struct btreeNode *rchild;   // 右孩子结点指针
}BTreeNode;

typedef struct btree            // 二叉树
{
	BTreeNode *root;            // 指向根节点的指针
}BTree;

BTree*  BTree_Create();//创建树

typedef void (*PFUNC)(BTreeNode *node, int level);//函数指针
//PFUNC是一个指针变量,它指向一个函数

1、插入位置 用二进制表示路径
0 代表左 1代表右 100(4) 左左右
右左左 001(1) ===> 无法确定步数
需要另一个参数:步数 (4 3) (1, 3)

2、挂载方式
btree 要插入的二叉树
data 要插入的数据
path 插入位置的路径
steps 从根节点开始走的步数
mw 原来的结点挂载到新节点后的方式

BOOL BTree_Insert(BTree *btree, BTreeData data, int path, int steps, MOUNTWAY mw);//插入结点

void BTree_Display(BTree *btree, PFUNC callback);//打印

BOOL BTree_Delete(BTree *btree, int path, int steps);//删除结点

int BTree_Count(BTree* btree);//获取树的结点数

int BTree_Height(BTree* btree);//获取树的高度

int BTree_Degree(BTree* btree);//获取树的度
void BTree_Destroy(BTree *btree);//销毁树

#endif // _BTREE_H_BTree.h文件

BTree.c文件

 #include "BTree.h"
 #include <stdlib.h>

创建树

    BTree* BTree_Create()
    {
    	BTree* btree = (BTree*)malloc(sizeof(BTree)/sizeof(char));//申请空间
    	if (NULL == btree)
    		return NULL;
    	
    	btree->root = NULL;   // 空的树
    	
    	return btree;//返回内存地址
    }

插入结点

    BOOL BTree_Insert(BTree *btree, BTreeData data, int path, int steps, MOUNTWAY mw)
    {
    	if (NULL == btree)//入口参数检测
    		return FALSE;
    	
    	BTreeNode *node = (BTreeNode*)malloc(sizeof(BTreeNode)/sizeof(char));//申请新的结点空间
    	if (NULL == node)
    		return FALSE;
    	
    	node->data = data;//赋值
    	node->lchild = NULL;
    	node->rchild = NULL;
    	
    	BTreeNode *parent = NULL;       // 父节点
    	BTreeNode *tmp = btree->root;   // 根节点
    	
    	int way = 0;
    	while (steps>0 && tmp != NULL)//找到要插入数位置,保存要插入位置的根结点
    	{
    		way = path & 1;
    		path >>= 1;
    		
    		parent = tmp;//需要保存要插入位置根结点的值
    		if (LEFT == way)
    			tmp = tmp->lchild;
    		else
    			tmp = tmp->rchild;
    		
    		steps--;
    	}
    	
    	if(LEFT == mw)//挂载
    		node->lchild = tmp;
    	else
    		node->rchild = tmp;
    	
    	if (parent != NULL)//考虑父结点位空的情况
    	{
    		if (LEFT == way)
    			parent->lchild = node;
    		else
    			parent->rchild = node;
    	}
    	else
    		btree->root = node;//根节点的父结点为空
    	
    	
    	return TRUE;
    }

删除结点

    void r_delete(BTreeNode *node)
    {
    	if (NULL == node)
    		return;
    	
    	r_delete(node->lchild);    // 删除左结点
    	r_delete(node->rchild);    // 删除右结点
    	free(node);                // 删除自己
    }

删除结点(与插入结点类似)

    BOOL BTree_Delete(BTree *btree, int path, int steps)
    {
    	if (NULL == btree)
    		return FALSE;
    
    	BTreeNode *parent = NULL;       // 父节点
    	BTreeNode *tmp = btree->root;   // 根节点
    	
    	int way = 0;
    	while (steps>0 && tmp != NULL)
    	{
    		way = path & 1;
    		path >>= 1;
    		
    		parent = tmp;
    		if (LEFT == way)
    			tmp = tmp->lchild;
    		else
    			tmp = tmp->rchild;
    		
    		steps--;
    	}
    	
    	if (NULL != parent)
    	{
    		if (LEFT == way)
    			parent->lchild = NULL;
    		else
    			parent->rchild = NULL;
    	}
    	else
    		btree->root = NULL;
    	
    	
    	r_delete(tmp);
    	
    	return TRUE;
    }

获取树的结点:左结点数+右结点数+1(根结点)

    int r_count(BTreeNode *node)
    {
    	if (NULL == node)
    		return 0;
    	
    	int lc = r_count(node->lchild);    // 左子树的结点数
    	int rc = r_count(node->rchild);    // 右子树的结点数
    	
    	return lc+rc+1;
    }

    int BTree_Count(BTree* btree)
    {
    	if (NULL == btree)
    		return 0;
    	
    	return r_count(btree->root);
    }

获取树的高度:左子树的高度与右子树的高度中大的值+1

   int r_height(BTreeNode *node)
    {
    	if (NULL == node)
    		return 0;
    	
    	int lh = r_height(node->lchild);    // 左子树的高度
    	int rh = r_height(node->rchild);    // 右子树的高度
    	
    	return (lh>rh?lh:rh)+1;
     }
     
     int BTree_Height(BTree* btree)
        {
        	if (NULL == btree)
        		return 0;
        	
        	return r_height(btree->root);
        }

获取树的度:左子树的度与右子树的度中大的值(假如根节点的度为1时)
(这个是重点)

      int r_degree(BTreeNode *node)
        {
        	if (NULL == node)
        		return 0;
        	
        	int degree = 0;
        	if (NULL != node->lchild)
        		degree++;
        	
        	if (NULL != node->rchild)
        		degree++;
        	
        	if (1 == degree)
        	{
        		int ld = r_degree(node->lchild);    // 左子树的度
        		int rd = r_degree(node->rchild);    // 右子树的度
        		
        		if (degree < ld)
        			degree = ld;
        		if (degree < rd)
        			degree = rd;
        	}
        	
        	return degree;
        }
       
        int BTree_Degree(BTree* btree)
        {
        	if (NULL == btree)
        		return 0;
        	
            	return r_degree(btree->root);
           }

销毁树

    void BTree_Destroy(BTree *btree)
       {
             if (NULL == btree)
                	return;
                	
             r_delete(btree->root);   // 删除根节点
       	     free(btree);             // 删除树
     }

打印(运用递归的方式打印)
具体打印方式由main函数进行定义

void r_display(BTreeNode *node, PFUNC callback, int level)
{
	callback(node, level);  // 1、打印自己
	
	if (NULL == node)
	{
		return;
	}
		
	if (node->lchild != NULL || node->rchild != NULL)
	{
		r_display(node->lchild, callback, level+1);  // 2、打印左结点
		
		r_display(node->rchild,  callback, level+1);  // 3、打印右结点	
	}
}
    
void BTree_Display(BTree *btree, PFUNC callback)
{
	if (NULL == btree)
		return;
	
	r_display(btree->root, callback, 1);
}

前序遍历(递归)

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);  // 根
}

main.c文件

   #include <stdio.h>
   #include "BTree.h"
    
void myprint(BTreeNode *node, int level)//用类似于tree的方式来打印
{
	int i;
	for (i = 1; i < level; i++)
	{
		printf ("----");
	}
	
	if (node != NULL)
		printf ("%c\n", node->data);
	else
		printf ("\n");
}

    int main()
    {
    	BTree* btree = BTree_Create();
    	if (NULL == btree)
    		return -1;
    	
    	// printf ("二叉树创建成功\n");
    	
    	BTree_Insert(btree, 'A', 0, 0, LEFT);
    	BTree_Insert(btree, 'B', 0, 1, LEFT);
    	BTree_Insert(btree, 'C', 1, 1, LEFT);
    	BTree_Insert(btree, 'D', 0, 2, LEFT);
    	BTree_Insert(btree, 'E', 2, 2, LEFT);
    	BTree_Insert(btree, 'F', 1, 2, LEFT);
    	BTree_Insert(btree, 'J', 6, 3, LEFT);
    	BTree_Insert(btree, 'H', 1, 3, LEFT);
    	
    	BTree_Display(btree, myprint);
    	printf ("前序遍历: ");
    	pre_order(btree->root);
    	printf ("\n");
    	
    	
    	printf ("中序遍历: ");
    	mid_order(btree->root);
    	printf ("\n");
    	
    	printf ("后序遍历: ");
    	last_order(btree->root);
    	printf ("\n");
    	return 0;
    }

验证结果为:

在这里插入图片描述

非递归方式实现前序遍历(借助链式栈实现)

void pre1(BTreeNode *root)
{
	if(root == NULL)
		return;
	
	LinkStack *stack =  CreateStack();
	BTreeNode* p = root;
	
	while (p != NULL || !StackEmpty(stack))
	{
		while(p)
		{
			printf ("%4c", p->data);//打印
			Push(stack, p);//入栈
			p = p->lchild;//遍历左子树
		}
		
		if (!StackEmpty(stack))
		{
			Pop (stack, &p);//出栈
			p = p->rchild;//遍历右子树
		}
	}
}

非递归方式实现中序遍历 (借助链式栈来实现)

void mid1(BTreeNode *root)
{
	if(root == NULL)
		return;
	
	LinkStack *stack =  CreateStack();
	BTreeNode* p = root;
	
	while (p != NULL || !StackEmpty(stack))
	{
		while(p)
		{
			Push(stack, p);//入栈
			p = p->lchild;//遍历左子树
		}
		
		if (!StackEmpty(stack))
		{
			Pop (stack, &p);//出栈
			printf ("%4c", p->data);//打印
			p = p->rchild;//右子树遍历
		}
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值