数据结构之平衡二叉树的递归实现

平衡二叉树


  平衡二叉树,相对于二叉查找树多了旋转操作,保证了查找元素时每一次比较都能做到折半。


头文件列出了要用到的结构和一些宏
#pragma once
#include <windows.h>

#define NAME_SIZE 20
#define BUFFER_SIZE 40

typedef struct {
	TCHAR szHeroName[NAME_SIZE];
	int iHeroType;
	int iGoldPrice;
	int iOtherPrice;
}ITEM;

typedef struct node {
	ITEM item;
	int iHeight;
	struct node * pLeft;
	struct node * pRight;
}NODE;

typedef NODE * TREE;

void InitTree(TREE * pTree);

NODE * InsertNode(NODE * pRoot, const ITEM * pItem);

NODE * DeleteNode(NODE * pRoot, NODE * pNode);

NODE * DeleteItem(NODE * pRoot, const ITEM * pItem);

NODE * SearchItem(NODE * pRoot, const ITEM * pItem);

void VisitItem(NODE * pNode);

void PreOrder(NODE * pRoot);

void InOrder(NODE * pRoot);

void PostOrder(NODE * pRoot);

void DestroyTree(NODE * pRoot);

BOOL CheckAVL(NODE * pRoot);


用到的内部函数。旋转之后需要修改原子树根节点和旋转之后子树根节点的高度。
int GetHeight(NODE * pRoot)
{
	if (pRoot)
		return pRoot->iHeight;
	else
		return 0;
}

int GetBL(NODE * pRoot)
{
	if (pRoot)
		return GetHeight(pRoot->pLeft) - GetHeight(pRoot->pRight);
	else
		return 0;
}

NODE * Retate_LL(NODE * pRoot)
{
	NODE * pNode;

	pNode = pRoot->pLeft;
	pRoot->pLeft = pNode->pRight;
	pNode->pRight = pRoot;

	pRoot->iHeight = max(GetHeight(pRoot->pLeft), GetHeight(pRoot->pRight)) + 1;
	pNode->iHeight = max(GetHeight(pNode->pLeft), GetHeight(pNode->pRight)) + 1;

	return pNode;
}

NODE * Retate_RR(NODE * pRoot)
{
	NODE * pNode;

	pNode = pRoot->pRight;
	pRoot->pRight = pNode->pLeft;
	pNode->pLeft = pRoot;

	pRoot->iHeight = max(GetHeight(pRoot->pLeft), GetHeight(pRoot->pRight)) + 1;
	pNode->iHeight = max(GetHeight(pNode->pLeft), GetHeight(pNode->pRight)) + 1;

	return pNode;
}

NODE * Retate_LR(NODE * pRoot)
{
	pRoot->pLeft = Retate_RR(pRoot->pLeft);
	return Retate_LL(pRoot);
}

NODE * Retate_RL(NODE * pRoot)
{
	pRoot->pRight = Retate_LL(pRoot->pRight);
	return Retate_RR(pRoot);
}

NODE * MakeNode(const ITEM * pItem)
{
	NODE * pNew;

	if (pNew = (NODE *)malloc(sizeof(NODE)))
	{
		pNew->item = *pItem;
		pNew->iHeight = 1;
		pNew->pLeft = pNew->pRight = NULL;
	}

	return pNew;
}

int CheckHeight(NODE * pRoot)
{
	if (pRoot == NULL) return 0;
	return max(CheckHeight(pRoot->pLeft), CheckHeight(pRoot->pRight)) + 1;
}

  有了头文件和内部函数,可以实现接口函数了,插入和删除都需要从修改的位置到根节点检查平衡,这种从插入或删除的位置回溯到根节点的性质
决定了递归是一种比较好实现的方法。
  删除结点时并不是真正删除该结点,而是找到该节点左树枝部分最大的元素来代替要删除的结点,这样能保证左右结点和父节点的关系。
那么找到的那个最大元素也需要从它左半部分中找到最大的元素来代替它,直到找到左孩子为NULL的结点将其删除。
void InitTree(TREE * pTree)
{
	*pTree = NULL;
}

NODE * InsertNode(NODE * pRoot, const ITEM * pItem)
{
	if (pRoot == NULL)
		return MakeNode(pItem);
	else
	{
		if (lstrcmp(pRoot->item.szHeroName, pItem->szHeroName) > 0)
		{
			pRoot->pLeft = InsertNode(pRoot->pLeft, pItem);
			pRoot->iHeight = max(GetHeight(pRoot->pLeft), GetHeight(pRoot->pRight)) + 1;
			if (GetBL(pRoot) == 2)
			{
				if (GetBL(pRoot->pLeft) == 1)
					pRoot = Retate_LL(pRoot);
				else
					pRoot = Retate_LR(pRoot);
			}
		}
		else
		{
			pRoot->pRight = InsertNode(pRoot->pRight, pItem);
			pRoot->iHeight = max(GetHeight(pRoot->pLeft), GetHeight(pRoot->pRight)) + 1;
			if (GetBL(pRoot) == -2)
			{
				if (GetBL(pRoot->pRight) == -1)
					pRoot = Retate_RR(pRoot);
				else
					pRoot = Retate_RL(pRoot);
			}
		}
		return pRoot;
	}
}

NODE * DeleteNode(NODE * pRoot, NODE * pNode)
{
	if (pRoot == pNode)
	{
		NODE * p;
		if (pNode->pLeft == NULL)
		{
			p = pNode->pRight;
			free(pNode);
			return p;
		}
		else if (pNode->pRight = NULL)
		{
			p = pNode->pLeft;
			free(pNode);
			return p;
		}
		else
		{
			p = pNode->pLeft;
			while (p->pRight != NULL)
				p = p->pRight;
			pRoot->item = p->item;
			pRoot->pLeft = DeleteNode(pRoot->pLeft, p);
			pRoot->iHeight = max(GetHeight(pRoot->pLeft), GetHeight(pRoot->pRight)) + 1;
			if (GetBL(pRoot) == -2)
			{
				if (GetBL(pRoot->pRight) <= 0)
					pRoot = Retate_RR(pRoot);
				else
					pRoot = Retate_RL(pRoot);
			}
			return pRoot;
		}
	}
	else if (lstrcmp(pNode->item.szHeroName, pRoot->item.szHeroName) < 0)
	{
		pRoot->pLeft = DeleteNode(pRoot->pLeft, pNode);
		pRoot->iHeight = max(GetHeight(pRoot->pLeft), GetHeight(pRoot->pRight)) + 1;
		if (GetBL(pRoot) == -2)
		{
			if (GetBL(pRoot->pRight) <= 0)
				pRoot = Retate_RR(pRoot);
			else
				pRoot = Retate_RL(pRoot);
		}
		return pRoot;
	}
	else
	{
		pRoot->pRight = DeleteNode(pRoot->pRight, pNode);
		pRoot->iHeight = max(GetHeight(pRoot->pLeft), GetHeight(pRoot->pRight)) + 1;
		if (GetBL(pRoot) == 2)
		{
			if (GetBL(pRoot->pLeft) >= 0)
				pRoot = Retate_LL(pRoot);
			else
				pRoot = Retate_LR(pRoot);
		}
		return pRoot;
	}
}

NODE * SearchItem(NODE * pRoot, const ITEM * pItem)
{
	if (pRoot == NULL)
		return pRoot;

	if (lstrcmp(pRoot->item.szHeroName, pItem->szHeroName) < 0)
		return SearchItem(pRoot->pRight, pItem);
	else if (lstrcmp(pRoot->item.szHeroName, pItem->szHeroName) > 0)
		return SearchItem(pRoot->pLeft, pItem);
	else
		return pRoot;
}

NODE * DeleteItem(NODE * pRoot, const ITEM * pItem)
{
	NODE * pNode = SearchItem(pRoot, pItem);
	if (pNode == NULL)
		return NULL;
	return DeleteNode(pRoot, pNode);
}

void VisitItem(NODE * pNode)
{
	wprintf(TEXT("%s"), pNode->item.szHeroName);
	wprintf(TEXT("  %d$\n"), pNode->item.iGoldPrice);
}

void PreOrder(NODE * pRoot)
{
	if (pRoot != NULL)
	{
		VisitItem(pRoot);
		PreOrder(pRoot->pLeft);
		PreOrder(pRoot->pRight);
	}
}

void InOrder(NODE * pRoot)
{
	if (pRoot != NULL)
	{
		InOrder(pRoot->pLeft);
		VisitItem(pRoot);
		InOrder(pRoot->pRight);
	}
}

void PostOrder(NODE * pRoot)
{
	if (pRoot != NULL)
	{
		PostOrder(pRoot->pLeft);
		PostOrder(pRoot->pRight);
		VisitItem(pRoot);
	}
}

void DestroyTree(NODE * pRoot)
{
	if (pRoot == NULL)
		return;
	DestroyTree(pRoot->pLeft);
	DestroyTree(pRoot->pRight);
	free(pRoot);
}

BOOL CheckAVL(NODE * pRoot)
{
	if (pRoot == NULL)
		return TRUE;
	if (pRoot->iHeight != CheckHeight(pRoot))
		return FALSE;
	if (abs(CheckHeight(pRoot->pLeft) - CheckHeight(pRoot->pRight)) >= 2)
		return FALSE;
	if (!CheckAVL(pRoot->pLeft))
		return FALSE;
	if (!CheckAVL(pRoot->pRight))
		return FALSE;

	return TRUE;
}

  这些函数在控制台已经依依运行过了,之后通过win32编程利用这些接口做了一个小程序,一个王者荣耀英雄商店。




平台:windows10 vs2015
完整工程代码下载:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值