数据结构之查找

本文详细介绍了各种数据结构中的查找技术,包括顺序表查找、有序表查找(如折半查找、插值查找、斐波那契查找)、线性索引查找(稠密索引和分块索引)以及二叉排序树和平衡二叉树(AVL树)。还讨论了哈希表及其散列函数和冲突处理方法。这些查找方法各有优劣,适用于不同的场景。
摘要由CSDN通过智能技术生成

查找就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素。

顺序表查找

顺序表查找(sequential search)又叫线性查找,是最基本的查找技术,它的查找过程是:从表中第一个记录开始,逐个进行记录的关键字和给定值比较,若某个记录的关键字和给定值相等,则查找成功,找到所查的记录;如果查到最后一个记录,其关键字和给定值比较都不等时,则表中没有所查的记录,查找不成功

  1. 顺序表查找
    a为数组,key为要查找的关键字,a[i]==key则查找成功。
  2. 顺序表查找优化
    以上算法每次循环时都要对i是否越界,即是否小于等于n作判断。事实上,还可以有更好一点的办法,设置一个哨兵,可以解决不需要每次让i与n作比较,时间复杂度为O(n)

有序表查找

折半查找

折半查找又称为二分查找,它的前提是线性表中的记录必须是关键码有序,线性表必须采用顺序存储,时间复杂度O(logn)
在这里插入图片描述

插值查找

现在我们的问题是,为什么一定要折半,而不是折1/4或者折更多呢?插值查找时根据要查找的关键字key与查找表中最大最小记录的关键字比较后的查找方法,其核心就在于插值的计算公式:
k e y − a [ l o w ] a [ h i g h ] − a [ l o w ] \frac{key-a[low]}{a[high]-a[low]} a[high]a[low]keya[low]
mid = low + (high-low)*(key-a[low])/(a[high]-a[low]);
时间复杂度为O(logn),但对于表长较长,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找好得多。

斐波那契查找

除了插值查找,还可以利用黄金分割原理来实现查找,即斐波那契查找。

  1. 数组不够斐波那契对应数字长度,得补全a[i]=a[n]
  2. mid=low+F[k-1]-1
  3. 如果key<a[mid],则high=mid-1;k=k-1
  4. 如果key>a[mid],则low=mid+1;k=k-2
  5. 直到key=a[mid],程序结束
  6. 如果mid>n,则说明是补全数值,返回n

在这里插入图片描述

#include "stdio.h"    
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */

typedef int Status;	/* Status是函数的类型,其值是函数结果状态代码,如OK等 */

int F[100]; /* 斐波那契数列 */

/* 无哨兵顺序查找,a为数组,n为要查找的数组个数,key为要查找的关键字 ,i返回角标*/
int Sequential_Search(int *a, int n, int key)
{
    
	int i;
	for (i = 1; i <= n; i++)
	{
    
		if (a[i] == key)
			return i;
	}
	return 0;
}
/* 有哨兵顺序查找 */
//a为表,n为表长,key为要查找的数字,i返回数字角标
int Sequential_Search2(int *a, int n, int key)
{
    
	int i;
	a[0] = key;
	i = n;
	while (a[i] != key)
	{
    
		i--;
	}
	return i;
}

/* 折半查找 */
//a为表,n为表长,key为要查找的数字,mid返回数字角标
int Binary_Search(int *a, int n, int key)
{
    
	int low, high, mid;
	low = 1;	/* 定义最低下标为记录首位 */
	high = n;	/* 定义最高下标为记录末位 */
	while (low <= high)
	{
    
		mid = (low + high) / 2;	/* 折半 */
		if (key<a[mid])		/* 若查找值比中值小 */
			high = mid - 1;		/* 最高下标调整到中位下标小一位 */
		else if (key>a[mid])/* 若查找值比中值大 */
			low = mid + 1;		/* 最低下标调整到中位下标大一位 */
		else
		{
    
			return mid;		/* 若相等则说明mid即为查找到的位置 */
		}

	}
	return 0;
}

/* 插值查找 */
//a为表,n为表长,key为要查找的数字,mid返回数字角标
int Interpolation_Search(int *a, int n, int key)
{
    
	int low, high, mid;
	low = 1;	/* 定义最低下标为记录首位 */
	high = n;	/* 定义最高下标为记录末位 */
	while (low <= high)
	{
    
		mid = low + (high - low)*(key - a[low]) / (a[high] - a[low]); /* 插值 */
		if (key<a[mid])		/* 若查找值比插值小 */
			high = mid - 1;		/* 最高下标调整到插值下标小一位 */
		else if (key>a[mid])/* 若查找值比插值大 */
			low = mid + 1;		/* 最低下标调整到插值下标大一位 */
		else
			return mid;		/* 若相等则说明mid即为查找到的位置 */
	}
	return 0;
}

/* 斐波那契查找 */
//a为表,n为表长,key为要查找的数字,mid返回数字的角标
int Fibonacci_Search(int *a, int n, int key)
{
    
	int low, high, mid, i, k = 0;
	low = 1;	/* 定义最低下标为记录首位 */
	high = n;	/* 定义最高下标为记录末位 */
	while (n>F[k] - 1)
		k++;
	for (i = n; i<F[k] - 1; i++)
		a[i] = a[n];

	while (low <= high)
	{
    
		mid = low + F[k - 1] - 1;
		if (key<a[mid])
		{
    
			high = mid - 1;
			k = k - 1;
		}
		else if (key>a[mid])
		{
    
			low = mid + 1;
			k = k - 2;
		}
		else
		{
    
			if (mid <= n)
				return mid;		/* 若相等则说明mid即为查找到的位置 */
			else
				return n;
		}

	}
	return 0;
}

int main(void)
{
    
	int a[MAXSIZE + 1], i, result;
	int arr[MAXSIZE] = {
     0,1,16,24,35,47,59,62,73,88,99 };
	for (i = 0; i <= MAXSIZE; i++)
	{
    
		a[i] = i;
	}
	result = Sequential_Search(a, MAXSIZE, MAXSIZE);
	printf("Sequential_Search:%d \n", result);
	result = Sequential_Search2(a, MAXSIZE, 1);
	printf("Sequential_Search2:%d \n", result);

	result = Binary_Search(arr, 10, 62);
	printf("Binary_Search:%d \n", result);

	result = Interpolation_Search(arr, 10, 62);
	printf("Interpolation_Search:%d \n", result);

	F[0] = 0;//斐波那契数列,全局变量
	F[1] = 1;
	for (i = 2; i < 100; i++)
	{
    
		F[i] = F[i - 1] + F[i - 2];
	}
	result = 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值