数据结构与算法(C)—二叉树

本文变量命名前缀:

  1. 全局变量:g_
  2. 数组:a
  3. 指针:p
  4. 结构体:st
  5. unsigned int:ui

本文代码可以到Github下载:https://github.com/liyuewu-github/DataStructure

一、二叉树定义

/* 二叉树 */
typedef struct BiTreeNode{
	unsigned int uiValue;
	struct BiTreeNode *pstLeft;
	struct BiTreeNode *pstRight;
}BITREE_NODE_S;

二、构建二叉树

/* 递归构建二叉树 */
BITREE_NODE_S *BITREE_Create_recursive(BITREE_NODE_S *pstTreeRoot, BITREE_NODE_S *pstTreeNode)
{
	if (!pstTreeRoot) /*终止条件 */
		pstTreeRoot = pstTreeNode;
	else if (pstTreeNode->uiValue < pstTreeRoot->uiValue ) /* 左子树 */
		pstTreeRoot->pstLeft = BITREE_Create_recursive(pstTreeRoot->pstLeft, pstTreeNode);
	else /* 右子树 */
		pstTreeRoot->pstRight = BITREE_Create_recursive(pstTreeRoot->pstRight,pstTreeNode);

	return pstTreeRoot;
}

三、二叉树遍历

常见二叉树遍历由四种方式:

  1. 先序遍历:先访问树根,再访问左子节点,最后访问右子节点;
  2. 中序遍历:先访问左子节点,再访问树根,最后访问右子节点;
  3. 后序遍历:先访问左子节点,再访问右子节点,最后访问树根
  4. 层次遍历:从上到下打印二叉树;

递归实现。

/* 先序遍历 */
void BITREE_Pre_Foreach(BITREE_NODE_S *pstTreeRoot)
{
	if (! pstTreeRoot)
		return;
	printf(" value %u \r\n", pstTreeRoot->uiValue);
	BITREE_Pre_Foreach(pstTreeRoot->pstLeft);
	BITREE_Pre_Foreach(pstTreeRoot->pstRight);
}

/* 中序遍历 */
void BITREE_Mid_Foreach(BITREE_NODE_S *pstTreeRoot)
{
	if (!pstTreeRoot)
		return;
	BITREE_Mid_Foreach(pstTreeRoot->pstLeft);
	printf(" value %u \r\n", pstTreeRoot->uiValue);
	BITREE_Mid_Foreach(pstTreeRoot->pstRight);
}

/* 后序遍历 */
void BITREE_Post_Foreach(BITREE_NODE_S *pstTreeRoot)
{
	if (!pstTreeRoot)
		return;
	BITREE_Post_Foreach(pstTreeRoot->pstLeft);
	BITREE_Post_Foreach(pstTreeRoot->pstRight);
	printf(" value %u \r\n", pstTreeRoot->uiValue);
}

非递归实现。
递归实现二叉树遍历简洁又美观,不过递归在某些情况下性能不行。非递归实现二叉树考虑用栈结构(递归就是一种栈操作),使用栈结构将树节点压入栈中,再依次出栈,并访问出栈节点的右子树。
二叉树栈需要实现以下基本功能:

  • 数据结构定义;
  • 栈初始化;
  • 栈是否为空;
  • 入栈;
  • 出栈;
/* 二叉树栈 */
#define STACK_LEN  1024
typedef struct BiTree_Stack{
	BITREE_NODE_S *pastBiTreeRoot[STACK_LEN];
	unsigned int uiTop;
}BITREE_STACK_S;

BITREE_STACK_S g_stBiTree_Stack;


/* 初始化二叉树栈 */
void BITREE_NODE_Stack_Init(void)
{
	g_stBiTree_Stack.uiTop = 0;
	return;
}

/* 二叉树栈是否为空 */
int BITREE_NODE_Stack_IsEmpty(void)
{
	return (g_stBiTree_Stack.uiTop == 0);
}

/* 二叉树入栈 */
void BITREE_NODE_Stack_Push(BITREE_NODE_S *pstBiTreeNode)
{
	g_stBiTree_Stack.pastBiTreeRoot[g_stBiTree_Stack.uiTop++] = pstBiTreeNode;
	return;
}

/* 二叉树出栈 */
BITREE_NODE_S *BITREE_NODE_Stack_Pop(void)
{
	return g_stBiTree_Stack.pastBiTreeRoot[--g_stBiTree_Stack.uiTop] ;
}

非递归实现二叉树遍历。

/* 先序遍历 */
void BITREE_Pre_Foreach_NoRecursive(BITREE_NODE_S *pstTreeRoot)
{
	BITREE_NODE_S *pstForeach;
	
	pstForeach = pstTreeRoot;
	
	BITREE_NODE_Stack_Init();
	while ((pstForeach) || (!BITREE_NODE_Stack_IsEmpty()))
	{
		while (pstForeach)
		{
			printf(" value %u \r\n", pstForeach->uiValue);
			BITREE_NODE_Stack_Push(pstForeach);  /* 左节点入栈 */
			pstForeach = pstForeach->pstLeft;
		}
		if (!BITREE_NODE_Stack_IsEmpty())
		{
			pstForeach = BITREE_NODE_Stack_Pop(); /* 左节点出栈,从底到顶找右节点 */
			pstForeach = pstForeach->pstRight;
		}
	}

}

/* 中序遍历 */
void BITREE_Mid_Foreach_NoRecursive(BITREE_NODE_S *pstTreeRoot)
{
	BITREE_NODE_S *pstForeach;
	pstForeach = pstTreeRoot;

	BITREE_NODE_Stack_Init();
	while ((pstForeach) || (!BITREE_NODE_Stack_IsEmpty()))
	{
		while (pstForeach)
		{
			BITREE_NODE_Stack_Push(pstForeach); /* 根节点和左节点入栈 */
			pstForeach = pstForeach->pstLeft;
		}
		if (!BITREE_NODE_Stack_IsEmpty())
		{
			pstForeach = BITREE_NODE_Stack_Pop();  /* 左节点,根节点,右节点依次出栈 */
			printf("value %d\n", pstForeach->uiValue);
			pstForeach = pstForeach->pstRight;  /* 右节点入栈 */
		}
	}
	
}

层次遍历。
层次遍历需要使用队列完成。树根先入队再出队,依次将其左右子节点入队再依次出队。
二叉树队列需要实现以下基本功能:

  • 数据结构定义;
  • 队列初始化;
  • 队列是否为空;
  • 入队;
  • 出队;
/* 二叉树队列 */
#define QUEUE_LEN  1024
typedef struct BiTree_Node_Queue{
	BITREE_NODE_S *pstQueue[QUEUE_LEN];
	unsigned int uiFront;
	unsigned int uiRear;
}BITREE_NODE_QUEUE;

BITREE_NODE_QUEUE g_stBiTree_Queue;

void BITREE_NODE_QUEUE_INIT(void)
{
	g_stBiTree_Queue.uiFront = 0;
	g_stBiTree_Queue.uiRear = 0 ;
	return;
}

void BITREE_NODE_Queue_Enq(BITREE_NODE_S *pstTreeRoot)
{
	g_stBiTree_Queue.pstQueue[++g_stBiTree_Queue.uiRear] = pstTreeRoot;
	return;
}
BITREE_NODE_S *BITREE_NODE_Queue_Deq(void)
{
	return g_stBiTree_Queue.pstQueue[++g_stBiTree_Queue.uiFront] ;
}

int BITREE_NODE_Queue_IsEmp()
{
	return (g_stBiTree_Queue.uiFront == g_stBiTree_Queue.uiRear);
}

层次遍历。

/* 层次遍历 */
void BITREE_Layer_Foreach(BITREE_NODE_S *pstTreeRoot)
{
	BITREE_NODE_S *pstTmp;
	
	BITREE_NODE_Queue_Enq(pstTreeRoot);
	while(!BITREE_NODE_Queue_IsEmp())
	{
		pstTmp = BITREE_NODE_Queue_Deq();
		printf("value %d\n",pstTmp->uiValue);

		if (pstTmp->pstLeft)
			BITREE_NODE_Queue_Enq(pstTmp->pstLeft);
		if (pstTmp->pstRight)
			BITREE_NODE_Queue_Enq(pstTmp->pstRight);
	}
	return;
}

四、二叉树公共节点

如果是二叉搜索树,那么可以利用Key值大小找公共节点。

/* 树的公共节点 */
BITREE_NODE_S *BITREE_Get_Parent(BITREE_NODE_S *pstTreeRoot,BITREE_NODE_S *pstTreeNode1,BITREE_NODE_S *pstTreeNode2)
{
	if ((!pstTreeRoot) || (!pstTreeNode1) || (!pstTreeNode2))
	{
		return NULL;
	}

	if ((pstTreeRoot->uiValue < pstTreeNode1->uiValue) && (pstTreeRoot->uiValue < pstTreeNode2->uiValue))
	{
	    return BITREE_Get_Parent(pstTreeRoot->pstRight,pstTreeNode1,pstTreeNode2);
	}
	else if ((pstTreeRoot->uiValue > pstTreeNode1->uiValue) && (pstTreeRoot->uiValue > pstTreeNode2->uiValue))
	{
		return BITREE_Get_Parent(pstTreeRoot->pstLeft,pstTreeNode1,pstTreeNode2);
	}
	else
	{
		return pstTreeRoot;
	}

}

如果是普通二叉树,那么就找两个节点的最早遍历到的根节点,即得到公共节点。

BITREE_NODE_S *BITREE_Get_Parent1(BITREE_NODE_S *pstTreeRoot,BITREE_NODE_S *pstTreeNode1,BITREE_NODE_S *pstTreeNode2)
{
	BITREE_NODE_S *pstLeft;
	BITREE_NODE_S *pstRight;

	if ((!pstTreeRoot) || (pstTreeRoot == pstTreeNode1) || (pstTreeRoot == pstTreeNode2))
	{
		return pstTreeRoot;
	}
	pstLeft = BITREE_Get_Parent1(pstTreeRoot->pstLeft,pstTreeNode1,pstTreeNode2);
	pstRight = BITREE_Get_Parent1(pstTreeRoot->pstRight,pstTreeNode1,pstTreeNode2);

	if (pstLeft==NULL && pstRight==NULL)
	{
	    return NULL;
	}
	else if (pstLeft!=NULL && pstRight==NULL)
	{
		return pstLeft;
	}
	else if (pstLeft==NULL && pstRight!=NULL)
	{
		return pstRight;
	}
	else
	{
		return pstTreeRoot;
	}

}

五、测试代码

void main()
{
	BITREE_NODE_S *pstTNode;
	BITREE_NODE_S *pstTRoot = NULL;
	int i;
	int iArray[] = {5,7,3,4,2};
	BITREE_NODE_S *apstTNode[5];

	for (i=0;i<5;i++)
	{
		pstTNode = malloc(sizeof(BITREE_NODE_S));
		memset(pstTNode, 0, sizeof(BITREE_NODE_S));
		pstTNode->uiValue = iArray[i];
		apstTNode[i] = pstTNode;
		pstTRoot = BITREE_Create_recursive(pstTRoot, pstTNode);
	}

	//BITREE_Pre_Foreach(pstTRoot); /* 先序递归 */
	//BITREE_Mid_Foreach(pstTRoot); /* 中序递归 */
	BITREE_Post_Foreach(pstTRoot); /* 后序递归 */

	printf("\n");
	
	BITREE_NODE_QUEUE_INIT();
	BITREE_Layer_Foreach(pstTRoot);

	BITREE_Pre_Foreach_NoRecursive(pstTRoot);  /* 先序非递归 */
	//BITREE_Mid_Foreach_NoRecursive(pstTRoot);  /* 中序非递归 */
	//BITREE_Post_Foreach_NoRecursive(pstTRoot);  /* 后序非递归 */
	
	printf("\ndepth %d \n", BITREE_Depth(pstTRoot));
	{
		BITREE_NODE_S *pstNode;
		BITREE_NODE_S *pstNode1;

		pstNode = BITREE_Get_Parent(pstTRoot,apstTNode[3],apstTNode[4]);
		printf("parent %d\n",pstNode->uiValue);
		pstNode1 = BITREE_Get_Parent1(pstTRoot,apstTNode[3],apstTNode[4]);
		printf("parent %d\n",pstNode1->uiValue);
	}

}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值