您的位置:首页 > 理论基础 > 数据结构算法

数据结构大总结系列之折半查找与动态查找树

2012-08-09 15:23 330 查看
数据结构大总结系列之查找
前言:

近来对各种算法的研究中,发现会用到大量的基本查找和排序算法,如折半查找,二叉查找树,快速排序,堆排序,归并排序等等,心血来潮,于是特对其做一个总结,作为一种模板库,以后便可性手捏来。

废话不多说,下面从各种查找算法入手,排序算法的总结在稍后的章节进行总结。

一,顺序表的查找:

这是最简单的查找,就是从表中最后一个记录开始,逐个进行记录的关键字和给定值的比较,直到查找成功过,算法的平均查找长度为3/4(n+1)。

二,有序表的查找(折半查找):

二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

#include <iostream>
using namespace std;
int binSearch(const int *Array,int start,int end,int key) {
int left=start,right=end;
int mid=0;
while (left<right) { //注释中为递归算法,执行效率低,不推荐
mid=left+(right-left)/2; //防止溢出,编程之美260页
/* if (key<Array[mid]) {
  return(binSearch(Array,left,mid,key));
  }
  else if(key>Array[mid]){
  return (binSearch(Array,mid+1,right,key));
  }
  else
  return mid;
  */
if (key<Array[mid]) {
right=mid-1;
}
else if(key>Array[mid]){
left=mid+1;
}
else
return mid;
}
return -1;
}

int main(){
int Array[5]={1,2,3,4,5};
cout<<binSearch(Array,0,4,3)<<endl;
}


三,二叉查找树:

二叉查找树种的左子树均小于它的根,右子树均大于它的根。

就不废话了,我相信只要学习过数据结构的童鞋,一定对二叉查找树的性质很清楚了,所以直接上代码:

我们先用模板来实现一个二叉树查找树的类:

#ifndef TreeNode_H
#define TreeNode_H

template<class NODETYPE>class Tree;
template<class NODETYPE>
class Tree_Node
{
friend class Tree<NODETYPE>;
public:
Tree_Node():leftPtr(0),data(0),rightPtr(0){};
Tree_Node(const NODETYPE &d):leftPtr(0),data(d),rightPtr(0){};
NODETYPE getData() const {
return data;
}
private:
Tree_Node<NODETYPE> *parent,*leftPtr,*rightPtr;
NODETYPE data;
};
#endif


#ifndef TREE_H
#define TREE_H

const int MAXNODE = 100;
#include <iostream>
using namespace std;
#include "TreeNode.h"

template<class NODETYPE>
class Tree
{
public:
Tree();
void insertNode(const NODETYPE &);
void inOrderTraversal() const;
Tree_Node<NODETYPE>* BSTreeSearch(const NODETYPE &value) const;
void BSTreeDel(Tree_Node<NODETYPE> *z);
private:
Tree_Node<NODETYPE> *rootPtr;
Tree_Node<NODETYPE>* BSTreeMinimim(Tree_Node<NODETYPE>* tree) const;
Tree_Node<NODETYPE>* BSTreeSuccessor(Tree_Node<NODETYPE>* x) const;
Tree_Node<NODETYPE>* BSTreeSearchHelper(Tree_Node<NODETYPE>*ptr,const NODETYPE &value) const;
void insertNodeHelper(Tree_Node<NODETYPE>**,const NODETYPE &);
void BSTreeDelHelper(Tree_Node<NODETYPE>**ptr,Tree_Node<NODETYPE>* z);
void inOrderTraversalHelper(Tree_Node<NODETYPE> *) const;
};

template<class NODETYPE>
Tree<NODETYPE>::Tree()
{
rootPtr = 0;
}
template<class NODETYPE>
void Tree<NODETYPE>::insertNode(const NODETYPE &value){
insertNodeHelper(&rootPtr,value);
}
//递归
/*template<class NODETYPE>
void Tree<NODETYPE>::insertNodeHelper(Tree_Node<NODETYPE>** ptr,const NODETYPE &value){
*ptr = new Tree_Node<NODETYPE>(value);
else
if(value<(*ptr)->data)
insertNodeHelper(&((*ptr)->leftPtr),value);
else if(value>(*ptr)->data)
insertNodeHelper(&((*ptr)->rightPtr),value);
else
cout<<value<<"dup"<<endl;
}*/
//非递归
template<class NODETYPE>
void Tree<NODETYPE>::insertNodeHelper(Tree_Node<NODETYPE>**ptr,const NODETYPE &value){
typedef Tree_Node<NODETYPE>* Position;
Position y = NULL;
Position x = *ptr;
Position z = new Tree_Node<NODETYPE>;
z->data = value;
z->parent = z->leftPtr = z->rightPtr = NULL;//初始化
//找到要插入的位置
while (x != NULL) {
y = x;
if (z->data < x->data) {
x= x->leftPtr;
} else {
x = x->rightPtr;
}
}    //和周边点增加关系
z->parent =y;
if (y == NULL) {
*ptr = z;
} else {
if (value < y->data) {
y->leftPtr = z;
} else {
y->rightPtr = z;
}
}
}

template<class NODETYPE>
void Tree<NODETYPE>::inOrderTraversal() const{
inOrderTraversalHelper(rootPtr);
}
//中序遍历递归版本
/*template<class NODETYPE>
void Tree<NODETYPE>::inOrderTraversalHelper(Tree_Node<NODETYPE> *ptr) const{
if(ptr != 0){
inOrderTraversalHelper(ptr->leftPtr);
cout<<ptr->data<<' ';
inOrderTraversalHelper(ptr->rightPtr);
}
}*/
template<class NODETYPE>
void Tree<NODETYPE>::inOrderTraversalHelper(Tree_Node<NODETYPE> *ptr) const{
if(ptr==NULL)
return;
Tree_Node<NODETYPE> *stack[MAXNODE];
int    top=-1;			//初始化栈顶指针
stack[++top]=ptr;//根指针入栈
Tree_Node<int> *s=ptr->leftPtr;   //s指向左子树
while(s!=NULL||top!=-1)//当存在节点(涉及到根下右子树)或者栈不为空,进行遍历
{
while(s!=NULL)     //如果存在节点,寻找最左子树并入栈
{
if(top>=MAXNODE-1){
return;
}
stack[++top]=s;//当前节点入栈
s=s->leftPtr;   //左子树进行遍历
}
if(top==-1){
return;
}
s=stack[top--];			//弹出栈顶元素到s中
cout<<s->data<<' ';
cout<<endl;//输出当前节点元素值
s=s->rightPtr;		//遍历右子树
}
}
template<class NODETYPE>
Tree_Node<NODETYPE>* Tree<NODETYPE>::BSTreeSearch(const NODETYPE &value) const{
return BSTreeSearchHelper(rootPtr,value);
}
//递归版本
/*template<class NODETYPE>
Tree_Node<NODETYPE>* Tree<NODETYPE>::BSTreeSearchHelper(Tree_Node<NODETYPE>*ptr,const NODETYPE &value) const{
if (ptr == NULL || value == ptr->data) {
return ptr;
}
if (value < ptr->data) {
return BSTreeSearchHelper(ptr->leftPtr, value);
} else {
return BSTreeSearchHelper(ptr->rightPtr, value);
}
}*/
//非递归版本
template<class NODETYPE>
Tree_Node<NODETYPE>* Tree<NODETYPE>::BSTreeSearchHelper(Tree_Node<NODETYPE>*ptr,const NODETYPE &value) const{
while (ptr != NULL && value != ptr->data) {
if (value < ptr->data) {
ptr = ptr->leftPtr;
} else {
ptr = ptr->rightPtr;
}
}
return ptr;
}
template<class NODETYPE>
void Tree<NODETYPE>::BSTreeDel(Tree_Node<NODETYPE> *z){
BSTreeDelHelper(&rootPtr,z);
}
template<class NODETYPE>
void Tree<NODETYPE>::BSTreeDelHelper(Tree_Node<NODETYPE>** ptr,Tree_Node<NODETYPE> *z) {
typedef Tree_Node<NODETYPE>* Position;
Position x, y;
//下边if-else确定要删除的节点y
if (z->leftPtr == NULL || z->rightPtr == NULL) {
y = z;//如果z没有子女或有一个子女,则要删除的结点就是z
} else {
//如果是第三种情况,则先删除z的后继
y = BSTreeSuccessor(z);
}    //x为y的子女或NULL
if (y->leftPtr != NULL) {
x = y->leftPtr;
} else {
x = y->rightPtr;
}    //通过修改y周边的关系,将y删除
//改变x的parent 是y的parent
if (x != NULL) {
x->parent = y->parent;
}    //上边的if第一种情况处理完毕
//下边的if-elseif-else第二种情况处理完毕
//y的parent的儿子是x,父子关系都修改,y即删除
if (y->parent == NULL) {
*ptr = x;
} else if (y == y->parent->leftPtr) {
y->parent->leftPtr = x;    }
else {
y->parent->rightPtr = x;
}    //处理第三种情况,把y中的内容复制到z中
if (y != z) {
z->data = y->data;
}
}

template<class NODETYPE>
Tree_Node<NODETYPE>* Tree<NODETYPE>::BSTreeSuccessor(Tree_Node<NODETYPE>* x) const {
if (x->rightPtr != NULL) {
return BSTreeMinimim(x->rightPtr);
}
Tree_Node<NODETYPE>* y = x->parent;
while (y != NULL && x == y-> rightPtr) {
x = y;
y = y->parent;
}
return y;
}

//返回二叉树最左边值(即最小值)的指针
template<class NODETYPE>
Tree_Node<NODETYPE>* Tree<NODETYPE>::BSTreeMinimim(Tree_Node<NODETYPE>* tree) const{
while (tree->leftPtr != NULL) {
tree = tree->leftPtr;
}
return tree;
}
#endif

测试代码:

#include <iostream>
#include "Tree.h"
#include <iomanip>

using namespace std;

int main(){
Tree<int> bSTree;
int k;
//while(cin>>k)//ctrl+z
for(k=5;k>=0;--k)
bSTree.insertNode(k);
bSTree.BSTreeDel(bSTree.BSTreeSearch(4));
bSTree.inOrderTraversal();
}


四,二叉平衡树及红黑树:

平衡二叉搜索树(Balanced Binary Tree)具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。常用算法有红黑树、AVL、Treap、伸展树等。在平衡二叉搜索树中,我们可以看到,其高度一般都良好地维持在O(log2n),大大降低了操作的时间复杂度。

下面先谈谈二叉树,平衡二叉树及红黑树的区别:

二叉树:是一种好的数据结构,能够比较高效的查找待查找的数据,但左右子树可能相差太大,导致其性能不是很理想,为此想到了使其左右子树的深度相差不要太大,以期提高查找的效率。

平衡二叉树的追求的是全局均衡,如在做插入,删除操作时,需要调整整棵树,显然这是费时的,因此希望在做调整时,是局部调整,因此提出了红黑树,这样一种高效的数据结构(也是最变态的一种数据结构)。

两者的区别体现在概念和性能上。

由于在实际运用中,我们基本上都会去运用红黑树,如STL中的set/map/multiset/multimap关联容器

而相对于红黑树来说,平衡二叉树也就是小巫见大巫,所以这里我们着重讲解红黑树,由于时间原因平衡二叉树的算法将在稍后更新请谅解。

有关红黑树的相关介绍请查看博文数据结构大总结系列之红黑树已经做了详细的介绍。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: