平衡二叉排序树的原理及实现

          上面讲的二叉排序树的查找顺序与树的形态密切相关;当树为完全二叉树是查找的效率很高;和折半查找的效率相同;但是树的不一定是完全二叉树;极端可能是单支树;其性能和链表相同;这是在一些系统上不能接收的;因此能不能对二叉排序树进行改进;这就是平衡二叉树;平衡二叉树就是在原来的二叉树中增加一个表示节点平衡因子的域;在插入的过程中随时对根节点检查是否平衡;如果不平衡就要用调整;

          一个重要的问题是怎么调整;有四种调整方式;分别是RR、LL、RL、 LR这几种方式;至于为什们会有这几种方式;需要你自己去画图;感受;体会;

         下面贴出来这几种方式的代码实现;这些代码很简单;但是必须要配上图才能更容易看的动;数据结构书本上都有;看了这些图后你写代码就能大脑中有一张图;写的自然很清楚;

      头文件;

# ifndef _SORT_

typedef int KeyType;

typedef struct
{
	KeyType key;
}DataType;

# endif

头文件;

# ifndef _SEQLIST_
# define _SEQLIST_

# include <iostream>
# include "Search.h"//引用这里的DataType;
using namespace std;

# define MAXSIZE 64

typedef struct
{
	DataType data[MAXSIZE];
	int length;
}SeqList, * PSeqList;

typedef struct Node
{
	DataType elem;
	struct Node * lchild;
	struct Node * rchild;
}BSTree, * PBSTree;

//线性表查找基本准备;
PSeqList Init_SeqList(void);
bool Full_SeqList(PSeqList p);
int Push_SeqList(PSeqList p, KeyType keyValue);
void Traversal_SeqList(PSeqList p);
ostream & operator<<(ostream & os, DataType dataValue);

//基于线性表的查找方法;

//顺序查找;
int SeqSearch(PSeqList p, KeyType key);

//折半查找;
int BinSearch(PSeqList p, KeyType key);

//二叉排序树插入;
void BSTreeInsert(PBSTree * ppt, KeyType key);

//二叉排序树查找;
PBSTree BSTreeSearch(PBSTree pt, KeyType key);

//二叉排序树中序遍历;
void InOrder(PBSTree pt);

//二叉树删除;
int BSTreeDelete(PBSTree * ppt, KeyType key);

//-----------------------------------------------哈希链表-----------------------------------------------

//哈希基表长度;
# define SIZE 13

//哈希链表节点;
typedef struct HashLinkListNode
{
	DataType data;
	struct HashLinkListNode * next;
}HashLinkListNode, * PHashLiskListNode;

//哈希基表节点;
typedef struct HashBaseListNode
{
	DataType data;
	int len;
	HashLinkListNode * firstnode;
}HashBaseListNode, * PHashBaseListNode;

//哈希表;
typedef struct
{
	HashBaseListNode elem[SIZE];
	int length;
}HashTable, * PHashTable;

//哈希函数 ;
int HashFunction(KeyType key);
//哈希表创建;
PHashTable CreateHashTable(void);
//哈希表插入;
bool HashTableInsert(PHashTable p, KeyType key);
//遍历哈希表;
void HashTableTraversal(PHashTable p);

//-----------------------------------------------平衡二叉排序树-----------------------------------------------

//平衡二叉排序树节点;
typedef struct AVLNode
{
	DataType data;//数据域;
	int bf;//记录节点的平衡因子;只能是{ -2、-1、 0、 1、 2 };
	struct AVLNode * lchild;//左孩子指针;
	struct AVLNode * rchild;//右孩子指针;
}AVLNode, * PAVLTree;

//LL型旋转;
PAVLTree LL_Rotate(PAVLTree a);

//RR型旋转;
PAVLTree RR_Rotate(PAVLTree a);

//LR型旋转;
PAVLTree LR_Rotate(PAVLTree a);

//RL型旋转;
PAVLTree RL_Rotate(PAVLTree a);

//平衡二叉排序树插入;
void AVLInsert(PAVLTree * pp, KeyType key);

//平衡二叉排序树中序遍历;
void Inorder(PAVLTree p);

#endif

实现文件;

这其中最终要的是插入的实现;因为在插入的同时检查平衡因子进行调整;前提是要先看懂四种调整的方式;

只有插入的同时调整好;使其更接近完全二叉树才能是查找效率很高;

# include "SeqList.h"

PSeqList Init_SeqList(void)
{
	PSeqList p = (PSeqList)malloc(sizeof(SeqList));

	if (NULL != p)
	{
		p->length = 0;
		return p;
	}
	else
	{
		cout << "Memory allocate is error! " << endl;
		system("pause");
		exit(0);
	}
}


bool Full_SeqList(PSeqList p)
{
	if (p->length >= MAXSIZE)
	{
		return true;
	}
	else
	{
		return false;
	}
}

int Push_SeqList(PSeqList p, KeyType keyValue)
{
	if (Full_SeqList(p))
	{
		cout << "SeqList is full! " << endl;

		return -1;
	}

	p->data[p->length].key = keyValue;
	p->length++;

	return 0;
}

void Traversal_SeqList(PSeqList p)
{
	for (int i = 0; i < p->length; i++)
	{
		cout << p->data[i] << " ";
	}
	cout << endl;

	return;
}

ostream & operator<<(ostream & os, DataType dataValue)
{
	cout << dataValue.key;

	return os;
}

//基于线性表的查找方法;;

//顺序查找;
int SeqSearch(PSeqList p, KeyType key)
{
	int i = 0;
	p->data[p->length].key = key;
	while (p->data[i].key != key)//使用这种带前哨站的算法必须是非满表;不然出错;
	{
		i++;
	}

	if (i == p->length)
	{
		return -1;
	}
	else
	{
		return i;
	}

	//for (int i = 0; i < p->length; i++)
	//{
	//	if (p->data[i].key == key)
	//	{
	//		return i;
	//	}
	//}

	return -1;
}

//折半查找;
int BinSearch(PSeqList p, KeyType key)
{
	int low = 0;
	int mid = 0;
	int high = p->length - 1;

	while (low <= high)
	{
		mid = (low + high) / 2;

		if (key == p->data[mid].key)
		{
			return mid;
		}
		else if (key > p->data[mid].key)
		{
			low = mid + 1;
		}
		else
		{
			high = mid - 1;
		}
	}

	return -1;
}

//二叉排序树插入;
void BSTreeInsert(PBSTree * ppt, KeyType key)
{
	PBSTree t = NULL;

	if (*ppt == NULL)
	{
		t = (PBSTree)malloc(sizeof(BSTree));
		t->elem.key = key;
		t->lchild = NULL;
		t->rchild = NULL;

		*ppt = t;
	}
	else
	{
		if (key < ((*ppt)->elem).key)
		{
			BSTreeInsert(&((*ppt)->lchild), key);
		}
		else
		{
			BSTreeInsert(&((*ppt)->rchild), key);
		}
	}

	return;
}

//二叉排序树查找;
PBSTree BSTreeSearch(PBSTree pt, KeyType key)
{
	if (NULL == pt)
	{
		return NULL;
	}

	if (key == pt->elem.key)
	{
		return pt;
	}
	else if (key < pt->elem.key)
	{
		BSTreeSearch(pt->lchild, key);
	}
	else
	{
		BSTreeSearch(pt->rchild, key);
	}
}

//二叉排序树中序遍历;
void InOrder(PBSTree pt)
{
	if (NULL != pt)
	{
		InOrder(pt->lchild);
		cout << pt->elem.key << " ";
		InOrder(pt->rchild);
	}
}

//二叉树删除;
int BSTreeDelete(PBSTree * ppt, KeyType key)
{
	PBSTree pre = NULL;
	PBSTree p = *ppt;
	PBSTree q = NULL;
	PBSTree s = NULL;

	//查找要插入的节点和前驱节点;
	while ((NULL != p) && (p->elem.key != key))
	{
		pre = p;

		if (key < p->elem.key)
		{
			p = p->lchild;
		}
		else
		{
			p = p->rchild;
		}
	}

	//检测是否没有查找到;
	if (NULL == p)
	{
		return 0;
	}

	if (NULL == p->lchild)//没有左孩子;这里需要用到前驱节点;
	{
		if (NULL == pre)//待删除的节点是根节点;
		{
			*ppt = p->rchild;
		}
		else if (pre->lchild == p)//待删除的节点是其前驱的左节点;
		{
			pre->lchild = p->rchild;
		}
		else//待删除节点是其前驱的右节点;
		{
			pre->rchild = p->rchild;
		}

		free(p);

		return 1;
	}
	else//没有右孩子;
	{
		q = p;
		s = p->lchild;

		while (s->rchild)
		{
			q = s;
			s = s->rchild;
		}

		if (p == q)
		{
			p->lchild = s->lchild;
		}
		else
		{
			q->rchild = s->lchild;
		}
		p->elem = s->elem;

		free(s);

		return 1;
	}
}

//哈希函数;
int HashFunction(KeyType key)
{
	return (key % 13);
}

//创建哈希表;
PHashTable CreateHashTable(void)
{
	PHashTable p = (PHashTable)malloc(sizeof(HashTable));

	if (NULL != p)
	{
		for (int i = 0; i < SIZE; i++)
		{
			p->elem[i].firstnode = NULL;
			p->elem[i].len = 0;
			p->elem[i].data = { 0 };
		}
		p->length = 0;

		return p;
	}
	else
	{
		cout << "Memory allocate is error! " << endl;
		system("pause");
		exit(0);
	}
}

//哈希表插入;
bool HashTableInsert(PHashTable p, KeyType key)
{
	int sub = HashFunction(key);
	if (0 == p->elem[sub].len)
	{
		p->elem[sub].data.key = key;
		p->elem[sub].len++;
		p->length++;
	}
	else
	{
		HashLinkListNode * t = (HashLinkListNode *)malloc(sizeof(HashLinkListNode));
		if (NULL == t)
		{
			return false;
		}
		t->data.key = key;
		t->next = p->elem[sub].firstnode;
		p->elem[sub].firstnode = t;
		p->elem[sub].len++;
		p->length++;
	}

	return true;
}

//遍历哈希表;
void HashTableTraversal(PHashTable p)
{
	for (int i = 0; i < SIZE; i++)
	{
		if (p->elem[i].len == 1)
		{
			cout << p->elem[i].data.key << endl;
		}
		else if (p->elem[i].len > 1)
		{
			cout << p->elem[i].data.key << endl;
			PHashLiskListNode q = p->elem[i].firstnode;
			while (NULL != q)
			{
				cout << q->data.key << endl;
				q = q->next;
			}
		}
		else
		{
			;
		}
	}
}


//LL型旋转;
PAVLTree LL_Rotate(PAVLTree a)
{
	PAVLTree b = a->lchild;
	a->lchild = b->rchild;
	b->rchild = a;
	a->bf = b->bf = 0;

	return b;
}

//RR型旋转;
PAVLTree RR_Rotate(PAVLTree a)
{
	PAVLTree b = a->rchild;
	a->rchild = b->lchild;
	b->lchild = a;
	a->bf = b->bf = 0;

	return b;
}

//LR型旋转;
PAVLTree LR_Rotate(PAVLTree a)
{
	PAVLTree b = a->lchild;
	PAVLTree c = b->rchild;

	b->rchild = c->lchild;
	a->lchild = c->rchild;
	c->lchild = b;
	c->rchild = a;

	if (c->bf == 1)
	{
		b->bf = 0;
		a->bf = -1;
	}
	else if (c->bf == -1)
	{
		b->bf = 1;
		a->bf = 0;
	}
	else
	{
		a->bf = b->bf = 0;
	}

	c->bf = 0;

	return c;
}

//RL型旋转;
PAVLTree RL_Rotate(PAVLTree a)
{
	PAVLTree b = a->rchild;
	PAVLTree c = b->lchild;

	a->rchild = c->lchild;
	b->lchild = c->rchild;
	c->lchild = a;
	c->rchild = b;

	if (c->bf == 1)
	{
		a->bf = 0;
		b->bf = -1;
	}
	else if (c->bf == -1)
	{
		a->bf = 1;
		b->bf = 0;
	}
	else
	{
		a->bf = b->bf = 0;
	}

	c->bf = 0;

	return c;
}

//平衡二叉排序树插入;
void AVLInsert(PAVLTree * pp, KeyType key)
{
	PAVLTree prea = NULL;//指针变量a的前驱节点指针;
	PAVLTree a = NULL;//距离插入点最近的平衡因子部位0的节点指针;
	PAVLTree b = NULL;//用于最后判断使用何种旋转的辅助指针变量;
	PAVLTree prep = NULL;//指针变量p的前驱节点指针;插入式必须知道前驱节点指针;
	PAVLTree p = NULL;//活动指针;用于循环遍历;

	//生成新插入节点;
	PAVLTree s = (PAVLTree)malloc(sizeof(AVLNode));
	s->data.key = key;
	s->lchild = s->rchild = NULL;
	s->bf = 0;

	//AVL树为空;新增节点为跟节点;
	if (NULL == *pp)
	{
		*pp = s;
		return;
	}

	//初始化;
	a = *pp;
	prea = NULL;
	p = *pp;
	prep = NULL;

	//查找最小不平衡子树和最终插入位置(保存在prep中);
	while (NULL != p)
	{
		//该关键字已存在AVL树种;
		if (p->data.key == s->data.key)
		{
			return;
		}

		//循环靠近距离插入点最近的平衡因子不为0的节点;
		if (p->bf != 0)
		{
			a = p;
			prea = prep;
		}

		//记录p的前驱节点指针;
		prep = p;

		//根据键值判断向左子树搜索还是向右子树搜索;
		if (s->data.key < p->data.key)
		{
			p = p->lchild;
		}
		else
		{
			p = p->rchild;
		}
	}

	//将s插入正确位置;
	if (s->data.key < prep->data.key)
	{
		prep->lchild = s;
	}
	else
	{
		prep->rchild = s;
	}

	//修改相关节点的平衡因子;
	p = a;
	while (p != s)
	{
		if (s->data.key < p->data.key)
		{
			p->bf++;
			p = p->lchild;
		}
		else
		{
			p->bf--;
			p = p->rchild;
		}
	}

	//插入节点后判断有没有破坏树的平衡性;
	if (a->bf > -2 && a->bf < 2)
	{
		return;//没有破坏树的平衡性;不需要进行平衡化旋转;
	}

	//进行平衡化旋转;
	if (a->bf == 2)
	{
		b = a->lchild;

		if (b->bf == 1)
		{
			p = LL_Rotate(a);
		}
		else
		{
			p = LR_Rotate(a);
		}
	}
	else
	{
		b = a->rchild;

		if (b->bf == -1)
		{
			p = RR_Rotate(a);
		}
		else
		{
			p = RL_Rotate(a);
		}
	}

	//判断最小不平衡字数是左子树还是右子树;
	if (NULL == prea)//a是跟节点;
	{
		*pp = p;
	}
	else if (prea->lchild == a)
	{
		prea->lchild = p;
	}
	else
	{
		prea->rchild = p;
	}

	//函数结束;
	return;
}

//平衡二叉排序树中序遍历;
void Inorder(PAVLTree p)
{
	if (NULL != p)
	{
		Inorder(p->lchild);
		cout << p->data.key << " ";
		Inorder(p->rchild);
	}

	return;
}

Main函数;这里都是测试;

# include "SeqList.h"

int main(int argc, char ** argv)
{
	PSeqList p = Init_SeqList();

	for (int i = 0; i < 10; i++)
	{
		Push_SeqList(p, i + 1);
	}

	cout << "------------------------SeqList Search------------------------" << endl;
	Traversal_SeqList(p);

	cout << "Your search position is : " << BinSearch(p, 0) << endl;
	cout << "Your search position is : " << BinSearch(p, 1) << endl;
	cout << "Your search position is : " << BinSearch(p, 5) << endl;
	cout << "Your search position is : " << BinSearch(p, 10) << endl;
	cout << "Your search position is : " << BinSearch(p, 11) << endl << endl;


	cout << "------------------------TreeList Search------------------------" << endl;

	PBSTree pt = NULL;
	PBSTree pp = NULL;
	BSTreeInsert(&pt, 34);
	BSTreeInsert(&pt, 18);
	BSTreeInsert(&pt, 76);
	BSTreeInsert(&pt, 13);
	BSTreeInsert(&pt, 25);
	BSTreeInsert(&pt, 52);
	BSTreeInsert(&pt, 82);
	BSTreeInsert(&pt, 20);
	BSTreeInsert(&pt, 67);
	BSTreeInsert(&pt, 91);
	BSTreeInsert(&pt, 58);
	BSTreeInsert(&pt, 73);

	InOrder(pt);
	cout << endl;

	if (NULL != (pp = BSTreeSearch(pt, 13)))
	{
		cout << pp->elem.key << endl;
	}

	BSTreeDelete(&pt, 34);

	InOrder(pt);
	cout << endl;

	cout << endl << "------------------------Hash Search------------------------" << endl;
	
	PHashTable pht = CreateHashTable();
	HashTableInsert(pht, 26);
	HashTableInsert(pht, 38);
	HashTableInsert(pht, 73);
	HashTableInsert(pht, 21);
	HashTableInsert(pht, 54);
	HashTableInsert(pht, 35);
	HashTableInsert(pht, 167);
	HashTableInsert(pht, 32);
	HashTableInsert(pht, 7);
	HashTableInsert(pht, 223);
	HashTableInsert(pht, 62);

	HashTableTraversal(pht);

	cout << endl << "------------------------AVL Search------------------------" << endl;

	PAVLTree t = NULL;
	AVLInsert(&t, 34);
	AVLInsert(&t, 18);
	AVLInsert(&t, 7);

	AVLInsert(&t, 69);
	AVLInsert(&t, 55);

	Inorder(t);

	cout << endl;
	system("pause");
	return 0;
}

到这里数据结构上很重要的一些代码都实现完了;后面还有对数据结构的其他内容进行学习和实现;

如红黑树;给自己加油;

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值