搜索算法
【仍在更新中,尚未完成】
顺序搜索
顺序搜索是运用枚举法的思想。
顺序搜索法 (Linear Search)从搜索表的一端开始顺序扫描,依次将搜索表中的结点关键字和键值进行比较,若两者相等,则搜索成功;若扫描结束后,还没有找到与键值相等的关键字,则搜索失败。
算法
采用for循环进行遍历
void LinearSearch(int* data, int key)
{
int flag = 0;//flag=0表示搜索失败
for (int i = 0; i < n; i++)
if (data[i] == key)//判断搜索是否成功
{
cout << "在第" << i << "个位置,找到" << key << endl;
flag = 1;//标志成功
}
if (flag == 0)//如果搜索失败
cout << "没有找到" << key << endl;
}
二分搜索
二分搜索法(Binary Search)只适用于搜索数据已被排序的情况。假设搜索数据是升序的,二分搜索法是将数据分成两等份,再比较键值与中间值的大小,如果键值小于中间值,可确定要搜索的数据为前半部分,否则为后半部分。如此进行下去,直到搜索成功或搜索不成功为止。
算法
void BinarySearch(int *data,int key,int n)
{ int z,mid,y,flag;//左中右下标,标识变量
z=0;y=n-1;
if(key<data[z]||key>data[y])
{ cout<<"键值超界,无法找到"<<key<<endl;
return;//什么都不做
}
flag=0;//假设未搜索到key
while(z<=y)
{ mid=(z+y)/2;//两分
if(key<data[mid])
{ y=mid-1;
if(z<=y)
cout<<"搜索左半部分,下标"
<<setw(2)<<z<<setw(2)<<"-"<<setw(2)<<y<<endl;
else
break;
}
else if(key>data[mid])
{ z=mid+1;
if(z<=y)
cout<<"搜索右半部分,下标"
<<setw(2)<<z<<setw(2)<<"-"<<setw(2)<<y<<endl;
else
break;
}
else
{ cout<<"在第 "<<mid<<" 个位置,搜索到"<<key<<endl;
flag=1;//搜索到key
break;
}
}
if(flag==0)
cout<<"没有搜索到"<<key<<endl;
}
二叉搜索树
二叉搜索树就是排序二叉树。在树的数据结构段中,函数Create()是通过逐个结点插入的方式来创建排序二叉树的。因此,可以将此函数看作是二叉搜索树的插入函数Insert()。向二叉搜索树中插入一个新元素,应保持二叉树仍为二叉搜索树。
搜索
二叉搜索树的搜索算法使用while循环,从根结点开始搜索,将键值key与当前结点值进行比较。若key等于该结点的值,则搜索以成功而终止;若key小于 该结点的值,则继续搜索左子树;否则继续搜索右子树。只有搜索到达空子树时,搜索以失败而终止。 搜索函数的代码如下:
void Search(BinTree T,int key)
{ Node *p=T.root;//定义探测指针p并指向根结点
while(p)//当p不指向空值时
{ if(key==p->data)//如果键值等于父结点值
{ cout<<"找到"<<key<<endl;//输出找到信息
return;//什么都不做
}
else if(key<p->data)//如果键值小于父结点值
p=p->lChild;//搜索左子树
else if(key>p->data)//如果键值大于父结点值
p=p->rChild;//搜索右子树
}
cout<<"没有找到"<<key<<endl;//输出未找到信息
}
删除
二叉搜索树上删除一个结点,需保证删除后的二叉树仍然是二叉搜索树。为了讨论方便,假定被删除结点为p,其父结点为f。删除过程可按下述两种情况分别处理:
- 如果被删除的结点 没有左子树,则只需把结点f指向p的指针,改为指向p的右子树,然后,再删除结点p。
- 如果被删除的结点 有左子树,则从结点p的左子树中选择结点值最大的结点 (它就是 的左子树中最右下角的结点,该结点 可能有左子树,但一定无右子树(如果有右子树,说明s不是最大,矛盾)),把结点s的值复制到结点p中,再将指向s的指针改为指向结点s的左子树,然后,再删除结点s。
代码实现如下:
void Delete(BinTree T,int key)
{ Node *f,*p,*q,*s;
p=T.root;f=NULL;//p指向根结点,f是p的双亲结点(直接前驱结点)
//搜索值为key的结点p
while(p&&p->data!=key)//当p不为空且p的值不等于键值时
{ f=p;
if(p->data>key)//如果p的值大于键值
p=p->lChild;//p向左子树下移
else//如果p的值不大于键值
p=p->rChild;//p向右子树下移
}
if(p==NULL)//如果删除结点不存在
{ cout<<"结点"<<key<<"不存在,无法删除"<<endl;
return;//什么都不做
}
if(p->lChild==NULL)//如果删除结点没有左子树
{ if(f==NULL)//如果删除结点为根结点
T.root=p->rChild;//树根结点右移
else if(f->lChild==p)//如果双亲结点的左孩子为删除结点
f->lChild=p->rChild;
else
f->rChild=p->rChild;
delete p;
}
else//如果删除结点有左子树
{ q=p;s=p->lChild;
while(s->rChild)
{ q=s;
s=s->rChild;
}
if(q==p)
q->lChild=s->lChild;
else
q->rChild=s->lChild;
p->data=s->data;
delete s;
}
}