数据结构课程设计 查找系统

192 阅读7分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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.