数据结构之查找算法,C语言实现

 查找指的是在大量的信息中寻找一个特定的信息元素。

目录

1.顺序查找

2.折半查找

3.哈希查找


平均查找长度ASL( Average Search Length):对给定k, 查找表L中记录比较次数的期望值(或平均值),用于衡量查找算法的效率。

1.顺序查找

ASL=O(n))

从线性表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值key相比较,若相等则表示查找成功;若扫描结束仍没有找到关键字等于key的结点,表示查找失败。

int seq_search(int *arr,int key,int len)
{
    int i=0;
    for(i=0;i<len;i++)
    {
        if(arr[i]==key)return i;
    }
    return -1;
}

int main()

{

    int arr[5] = { 10, 20, 5, 25, 1 };

    int ret = seq_search(arr, 25, 5);

    printf("ret pos=%d\n", ret);

    return 0;

}

2.折半查找

n-->∞时,ASL=O(log2 (n+1)

也称二分查找,用给定值key先与中间结点的关键字比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据k与该中间结点关键字的比较结果确定下一步查找哪个子表,直到查找到或查找结束发现表中没有这样的结点。

但查找的前提是数据序列是有序的顺序存储结构,要么升序排列要么降序排列。

void input(int *arr,int *key,int len)
{
    int i;        
    printf("输入数据\n");
    for(i=0;i<len;i++)
    {
        scanf("%d",&arr[i]);
    }
    printf("输入要查找的数据值\n");
    scanf("%d",key);
    printf("搜索结果为\n");
}

int bin_search(int *arr,int key,int len)
{
    int low=0,high=len-1,mid;
    while(low<=high)
    {
        mid=(low+high)/2;
        if(arr[mid]==key)return mid;
        else if(arr[mid]<key)low=mid+1;//说明key值可能在右半边,故缩小下界
        else high=mid-1;//说明key值可能在左半边,故缩小上界
    }
    return -1;//未找到返回-1
}

3.哈希查找

ASL=O(c),常数级

        要查找key=k的记录时,通过关系f就可得到相应记录的地址而获取记录,从而免去了key的比较过程。这个关系f就是所谓的Hash函数(或称散列函数、杂凑函数),记为H(key)。它实际上是一个地址映象函数,其自变量为记录的key,函数值为记录的存储地址(或称Hash地址)。

     另外,不同的key可能得到同一个Hash地址,即当keyl≠key2时,可能有H(key1)=H(key2),此时称key1和key2为同义词。这种现象称为“冲突”或“碰撞”,因为一个数据单位只可存放一条记录。选取Hash函数只能做到使冲突尽可能少,却不能完全避免。这就要求在出现冲突之后,寻求适当的方法来解决冲突记录的存放问题。

        本文选择质数除余法(也称保留余数法)作为构造Hash函数的方法,且为较为常用的方法。

设Hash表空间长度为m,选取一个不大于m的最大质数p,则H(key)=key%p

例:记录的key集合k={23,34,14,38,46, 16 ,68 ,15 ,07 ,31 ,26....},假设其哈希表长为m=21,
则取p=19

key : 23 34 14 38 ... 

则:H(key)=key%19 : 4  15   14  0  ...

        处理冲突的方法有开放地址法,链地址法,本文采用链地址法。发生冲突时,将各冲突记录链在一起,即同义词的记录存于同一链表。
        设H(key)取值范围(值域)为[0,m-l],建立头指针向量HP[m],HP[i](0≤i≤m-l)初值为空。凡H(key)=i的记录都链入头指针为HP[i]的链表
        另外,导致冲突还有一个因素是表的装填因子α,α=n/m,其中m为表长,n为表中记录个数。一般α在0.7~0.8之间,使表保持一定的空闲余量,以减少冲突和聚积现象。

以上面例子,k={23,34,14,38,46, 16 ,68 ,15 ,07 ,31 ,26},其记录数为11,另装填因子α=0.75,则取哈希表长m=n/α,向上取整为15。故取p=13;则哈希表构建如下:

链地址法解决冲突的优点: 无聚积现象; 删除表中记录容易实现。 而开放地址法的Hash表作删除时, 不能将记录所在单元置空, 只能作删除标记。

以下为质数除余法构造Hash和链地址法解决冲突的C语言实现

主函数:

/*===============================================
*   文件名称:main.c
*   创 建 者: xm    
*   创建日期:2022年08月03日
*   描    述:
================================================*/
#include "search.h"

int main(int argc, char *argv[])
{ 
	keytype data[N],key;//数据表和要查的目标数据

	//input(data,&key,N);
	//测试数据
	input_test(data,&key,N);
    int i;
	L_node *HP[m];//哈希表头,每个元素存储每条链表的头指针
	for(i=0;i<m;i++)//初始化表头
	{
		HP[i]=NULL;
	}
	for(i=0;i<N;i++)//遍历数据表建立哈希表
	{
		Set_Hash(HP,data[i]);
	}
	puts("-------------");
	L_node *ret=Hash_search(HP,key);
	if(ret==NULL)printf("未找到\n");
	else printf("有这个数据结点,其地址为%p\n",ret);
	

    return 0;
} 

模块文件:

/*===============================================
*   文件名称:seq_search.c
*   创 建 者:xm     
*   创建日期:2022年08月03日
*   描    述:
================================================*/
#include "search.h"
void input(int *arr,int *key,int len)
{
	int i;		
	printf("输入数据\n");
	for(i=0;i<len;i++)
	{
		scanf("%d",&arr[i]);
	}
	printf("输入要查找的数据值\n");
	scanf("%d",key);
	printf("搜索结果为\n");
}
//测试数据
void input_test(int *arr,int *key,int len)
{
	arr[0]=23;
	arr[1]=34;
	arr[2]=14;
	arr[3]=38;
	arr[4]=46;
	arr[5]=16;
	arr[6]=68;
	arr[7]=15;
	arr[8]=7;
	arr[9]=31;
	arr[10]=26;
	
	int i;
	for(i=0;i<len;i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n请输入要查找的数据\n");
	scanf("%d",key);
	puts("搜索结果");
	
}
int H(int key)//求哈希地址
{
	return key%P;
}

L_node *Hash_search(L_node *HP[m],keytype key)
{
	L_node *p=HP[H(key)];//通过Hash地址找到表头对应链表头指针
	
	while((p!=NULL) && (p->key!=key))
	{
		p=p->next;//产生冲突就取其链表下一结点
	}
	return p;//q若为NULL说明没找到这个数据,非空则找到且返回其结点地址
}
void Hash_insert(L_node *HP[m],L_node *new_node)//将数据结点插入哈希表
{
	int d;
	L_node *p=Hash_search(HP,new_node->key);//查找该数据结点在哈希表中位置
	if(p!=NULL) printf("记录已存在\n");//说明已有这个数据
	else {
		d=H(new_node->key);
		//头插法
		new_node->next=HP[d];
		HP[d]=new_node;
	}
}
void Set_Hash(L_node *HP[m],keytype key)
{
	L_node *new_node=(L_node *)malloc(sizeof(L_node));
	if(new_node==NULL)
	{
		printf("new_node malloc error\n");
		return ;
	}
	new_node->key=key;
	new_node->next=NULL;
		
	Hash_insert(HP,new_node);
}

头文件:

/*===============================================
*   文件名称:search.h
*   创 建 者:xm     
*   创建日期:2022年08月03日
*   描    述:
================================================*/
#ifndef _SEARCH_
#define _SEARCH_
#include <stdio.h>
#include <stdlib.h>
#define N 11
#define a 0.75 //装填因子
#define m 15 //哈希表长
#define P 13 //取不大于m的最大质数,这里根据测试数据表使用13

typedef int keytype; 
typedef struct link_node
{
	keytype key;
	struct link_node *next;
}L_node;

void input(int *arr,int *key,int len);
void input_test(int *arr,int *key,int len);
int H(int key);//哈希函数
void Set_Hash(L_node *HP[m],keytype key);//建立哈希表
L_node *Hash_search(L_node *HP[m],keytype key);//哈希查找
void Hash_insert(L_node *HP[m],L_node *new_node);//哈希插入

#endif

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值