上面讲的二叉排序树的查找顺序与树的形态密切相关;当树为完全二叉树是查找的效率很高;和折半查找的效率相同;但是树的不一定是完全二叉树;极端可能是单支树;其性能和链表相同;这是在一些系统上不能接收的;因此能不能对二叉排序树进行改进;这就是平衡二叉树;平衡二叉树就是在原来的二叉树中增加一个表示节点平衡因子的域;在插入的过程中随时对根节点检查是否平衡;如果不平衡就要用调整;
一个重要的问题是怎么调整;有四种调整方式;分别是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;
}
到这里数据结构上很重要的一些代码都实现完了;后面还有对数据结构的其他内容进行学习和实现;
如红黑树;给自己加油;