一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第28天,点击查看活动详情。
查找系统
1. 问题描述
设计一个查找系统,通过选择各种查找方法,输入数据后能完成查找并输出结果。
(1)设计一个菜单将要实现的功能显示出来,并有选择显示;
(2)分别实现顺序、折半查找、哈希表查找(哈希表可选取任意一种方法实现);
(3)二叉排序树必须实现构建、查找、插入、删除四个基本操作。
2. 算法思想
(1)顺序查找:
从查找表的一端开始,将给定值与逐个记录的关键字进行比较,若相等,则查找成功,给出该记录在查找表中的位置。若遍历整个查找表,仍未找到关键字,则查找失败。
(2)折半查找:
在有序表中,首先取表中记录的关键字与给定值进行比较。若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半子表中继续查找;若给定值大于中间记录的关键字,则在中间记录的右半子表中继续查找。重复上述过程,直到查找成功;或当前的查找区间无记录,这时查找失败。
(3)哈希查找:
首先在记录的关键字key与记录的存储位置y之间建立一个对应关系H,使得y=H(key),即每个关键字与唯一的一个存储位置H(key)相对应,H为哈希函数,该算法用到除留余数法,利用开放定址法中线性探测再散列解决冲突。
(4)二叉排序树的构建:
建立二叉排序树的过程就是从空树开始,不断向二叉排序树中插入结点的过程。
(5)二叉排序树的插入:
插入结点的过程如下: ①若二叉排序树bst为空,则为待插入关键字key申请结点,并作为根结点插入。 ②若二叉排序树bst非空,则为关键字key与根节点的关键字的值进行比较: 若key=bst->data,查找成功,不需要插入; 若keydata,沿左子树查找,若查找失败,将新结点插到合适的位置处; 若key>bst->data,沿右子树查找,若查找失败,将新结点插到合适的位置处。
(6)二叉排序树的查找:
二叉树的查找是从根结点开始,沿着某一个分支逐层向下比较的过程:
-
①若二叉排序树为空,查找失败。
-
②若二叉排序树非空,将给定值与根节点的关键字进行比较:
-
若给定值与根节点的关键字相同,则查找成功;
-
若给定值小于根节点的关键字,则在根节点的左子树上查找;
-
若给定值大于根节点的关键字,则在根结点的右子树上查找。
-
(7)二叉排序树的删除:
若要删除p结点,可以用二叉排序树的中序遍历序列中p结点的直接前驱或直接后继来代替p结点。而中序遍历序列中p结点的直接前驱必定是p结点左子树的最右下结点,它是所有小于p结点值的结点中关键字值最大的那一个。中序遍历序列中p结点的直接后继必定是p结点右子树的最左下结点,它是所有大于p结点值的结点中关键字值最小的那一个。此处设用p结点的左子树的最右下结点来代替p结点,即将左子树最右下结点的值赋给p结点(p->data=s->data),将左子树最右下结点的双亲结点的右孩子指向该结点的左孩子(q->rchild=s->lchild),然后删除该结点(free(s))。
3. C源代码
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include"Stack.h"
#define max 20
#define NULLKEY -32768
typedef struct{
int *data;
int length;
}SSTable;
void Display(SSTable ST)//元素显示
{
int i;
for (i = 1; i<=ST.length; i++)
{
printf("%4d", ST.data[i]);
}
printf("\n");
}
//建立查找表的顺序存储结构
void CreateSearchList(SSTable &ST,int m,int n)
{
ST.data=(int*)malloc(sizeof(int)*(max+1));
ST.length=max;
srand(time(0));
for(int i=1;i<=ST.length;i++)
{
ST.data[i]=rand()%n+m;
}
}
//快速排序
int Partition(SSTable &ST,int low,int high)
{
ST.data[0]=ST.data[low];
int pivotkey=ST.data[low];
while(low<high){
while(low<high && ST.data[high]>=pivotkey)
high--;
if(low<high)
ST.data[low++]=ST.data[high];
while(low<high && ST.data[low]<=pivotkey)
low++;
if(low<high)
ST.data[high--]=ST.data[low];
}
ST.data[low]=ST.data[0];
return low;
}
void Qsort(SSTable &ST,int low,int high)
{
int pivotloc;
if(low<high){
pivotloc=Partition(ST,low,high);
Qsort(ST,low,pivotloc-1);
Qsort(ST,pivotloc+1,high);
}
}
void QuickSort(SSTable &ST)
{
Qsort(ST,1,ST.length);
}
//顺序查找
int Search_seq(SSTable ST,int K)
{
int i=ST.length;
ST.data[0]=K;
while(ST.data[i]!=K)
i--;
return i;
}
void Search_Seq(SSTable ST)
{
int i,j,k,m,n;
printf("请输入m,n的值,产生m到n的随机数\n");
scanf("%d%d",&m,&n);
CreateSearchList(ST,m,n);
Display(ST);
printf("\n请输入要查找的关键字:\n");
scanf("%d",&k);
j=Search_seq(ST,k);
if(j==0)
{
printf("\n查找失败!\n");
}
else
printf("\n查找成功,%d元素在表中的位置是:%d\n",j,ST.data[j]);
}
//折半查找
int Search_bin(SSTable ST,int k)
{
int high,mid,low;
low=1;high=ST.length;
while(low<high)
{
mid=(low+high)/2;
if(k==ST.data[mid])
return mid;
else if(k<ST.data[mid])
high=mid-1;
else
low=mid+1;
}
}
void Search_Bin(SSTable ST)
{
int i,j,k,m,n;
printf("请输入m,n的值,产生m到n的随机数\n");
scanf("%d%d",&m,&n);
CreateSearchList(ST,m,n);
printf("排序前:\n");
Display(ST);
QuickSort(ST);
printf("排序后:\n");
Display(ST);
printf("\n请输入要查找的关键字:\n");
scanf("%d",&k);
i=Search_bin(ST,k);
if(i==0)
{
printf("\n查找失败!\n");
}
else
printf("\n查找成功,%d元素在表中的位置是:%d\n",ST.data[i],i);
}
//哈希查找
void InitHashTable(SSTable &ST)
{
int i;
ST.length = max;
ST.data = (int *)malloc(max*sizeof(int));
for (i = 0; i <ST.length; i++)
ST.data[i] = NULLKEY;
}
int Hash(int key)
{
return key % max; //这里使用的是除留余数法
}
void InsertHash(SSTable &ST, int key)
{
int addr = Hash(key); //根据关键字求取地址
while (ST.data[addr] != NULLKEY) //如果不为空,有冲突出现
addr = (addr + 1) % max; //这里使用开放定址法的线性探测
ST.data[addr] = key; //直到有空位后插入
}
bool SearchHash(SSTable &ST, int key, int &addr)
{
addr = Hash(key); //求取哈希地址
while (ST.data[addr] != key) //如果不为空,则存在冲突
{
addr = (addr + 1) % max; //开发定址法的线性探测
if (ST.data[addr] == NULLKEY || addr == Hash(key))
return false; //关键字不存在
}
return true; //查找成功返回
}
void Search_Hash(SSTable &ST)
{
int i,j,k,m,n,addr;
srand(time(0));
printf("请输入m,n的值,产生m到n的随机数\n");
scanf("%d%d",&m,&n);
InitHashTable(ST);
for(i=0;i<ST.length;i++)
{
k=rand()%n+m;
InsertHash(ST,k);
}
for (i=0; i<ST.length; i++)
{
printf("%4d", ST.data[i]);
}
printf("\n请输入需要查找的关键字:\n");
scanf("%d", &j);
bool status = SearchHash(ST, j,addr);
if (!status)
printf("\n查找失败!\n");
else
printf("\n查找成功!\n");
}
//二叉排序树查找
int SearchBST(BiTree bst,int k,BiTree &p)
{
BiTree s=bst;
BiTree f=NULL;
if(!s){
p=f;
return 0;
}
while(s!=NULL)
if(k==s->data){
p=s;return 1;
}
else if(k<s->data){
f=s;s=s->lchild;
}
else{
f=s;s=s->rchild;
}
p=f;
return 0;
}
//二叉排序树插入
void InsertBST(BiTree &bst,int e)
{
if(bst==NULL){
bst=(BiTree)malloc(sizeof(BiTNode));
bst->data=e;
bst->lchild=bst->rchild=NULL;
}
else{
BiTree p;
if(!SearchBST(bst,e,p)){
BiTree s=(BiTree)malloc(sizeof(BiTNode));
s->data=e;
s->lchild=s->rchild=NULL;
if(e<p->data)
p->lchild=s;
else
p->rchild=s;
}
}
}
//二叉排序树构建
void CreateBST(BiTree &bst,int m,int n){
bst=NULL;
int x,count=max;
BiTree p;
srand(time(0));
x=rand()%n+m;
printf("%4d",x);
while(count>1)
{
if(!SearchBST(bst,x,p))
InsertBST(bst,x);
x=rand()%n+m;
printf("%4d",x);
count--;
}
printf("\n");
}
//二叉排序树删除
void DeleteNode(BiTree &bst,int e)
{
BiTree q,pc,p=bst;
BiTree f=NULL;
while(p&&p->data!=e){
f=p;
if(e<p->data)
p=p->lchild;
else
p=p->rchild;
}
if(!p)
{
printf("该树中没有需要删除的结点\n");
return ;
}
if(p->lchild && p->rchild)
{
q=p;
BiTree s=p->lchild;
while(s->rchild)
{
q=s;
s=s->rchild;
}
p->data=s->data;
if(q == p)
q->lchild=s->lchild;
else
q->rchild=s->rchild;
free(s);
}
else{
if(p->lchild)
pc=p->lchild;
else
pc=p->rchild;
if(!f)
bst=pc;
else if(f->lchild==p)
f->lchild=pc;
else
f->rchild=pc;
free(p);
}
}
//中序遍历二叉排序树
void InOrderTraverse(BiTree bt)
{
StackPtr S;
BiTree p;
if(bt)
{
InitStack(S);
Push(S,bt);
while(!StackEmpty(S))
{
while(GetTop(S,p)&&p){
Push(S,p->lchild);
}
Pop(S,p);
if(!StackEmpty(S))
{
Pop(S,p);
printf("%4d",p->data);
Push(S,p->rchild);
}
}
}
}
//二叉排序树构建
void Create_BST(BiTree &bst)
{
int i,j,k,m,n;
printf("请输入m,n的值,产生m到n的随机数\n");
scanf("%d%d",&m,&n);
CreateBST(bst,m,n);
printf("\n中序遍历二叉排序树:\n");
InOrderTraverse(bst);
printf("\n");
}
//二叉排序树查找
void Search_BST(BiTree &bst)
{
BiTree p;
int i,k;
printf("\n插入前:\n");
InOrderTraverse(bst);
printf("\n请输入要查找的关键字:\n");
scanf("%d",&k);
i=SearchBST(bst,k,p);
if(i==0)
{
printf("\n查找失败!\n");
}
else
printf("\n查找成功!\n");
printf("\n");
}
//二叉排序树插入
void Insert_BST(BiTree &bst)
{
printf("\n插入前:\n");
InOrderTraverse(bst);
printf("\n请输入要插入的关键字:\n");
int k;
scanf("%d",&k);
InsertBST(bst,k);
printf("\n插入后:\n");
InOrderTraverse(bst);
}
//二叉排序树删除
void Delete_Node(BiTree &bst)
{
printf("\n删除前:\n");
InOrderTraverse(bst);
printf("\n请输入要删除的关键字:\n");
int k;
scanf("%d",&k);
DeleteNode(bst,k);
printf("\n删除后:\n");
InOrderTraverse(bst);
printf("\n");
}
void Menu()//查找系统菜单
{
SSTable ST;
BiTree bst;
while(1)
{
system("color b1");
printf("*=============================================================================================*\n");
printf("**&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&欢迎使用查找系统&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&**\n");
printf("** ①顺序查找 **\n");
printf("** ②折半查找 **\n");
printf("** ③哈希表查找 **\n");
printf("** ④二叉排序树构建 **\n");
printf("** ⑤二叉排序树查找 **\n");
printf("** ⑥二叉排序树插入 **\n");
printf("** ⑦二叉排序树删除 **\n");
printf("** 〇 退出 **\n");
printf("**&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&**\n");
printf("*===============================================================================================*\n");
printf("请输入您要选择的服务种类:(0 ~ 7)\n");
int num;
scanf("%d",&num);
switch(num)
{
case 1 :system("CLS");Search_Seq(ST);system("pause");break;
case 2 :system("CLS");Search_Bin(ST);system("pause");break;
case 3 :system("CLS");Search_Hash(ST);system("pause");break;
case 4 :system("CLS");Create_BST(bst);system("pause");break;
case 5 :system("CLS");Search_BST(bst);system("pause");break;
case 6 :system("CLS");Insert_BST(bst);system("pause");break;
case 7 :system("CLS");Delete_Node(bst);system("pause");break;
case 0 :system("CLS");printf("谢谢使用!");exit(0);system("pause");
default:system("CLS");printf("无效输入!\n");system("pause");
}
}
}
int main()
{
Menu();
return 0;
}
4. 小结
查找系统演示:
不足之处:查找系统中关键字是需要输入的,我为了减少测试的麻烦,就随机产生20是个m到n的关键字进行查找,需要先进行二叉树排序树构建,然后才能进行二叉排序树的查找、插入和删除操作。
5. 参考文献
[1] 赵永升,宋丽华,数据结构.北京:电子工业出版社,2019. [2] 严蔚敏,数据结构(C语言版).北京:清华大学出版社,2007.