查找之静态查找表

数据结构中查找分为如下部分:

  • 静态查找表
  • 动态查找表
  • 哈希表及其查找
以下分别对数据结构中的查找算法进行描述

一、静态查找表

1.顺序表查找

顺序查找(Sequential Search)又称为线性查找,是一种最简单的查找方法。

查找过程如下:
从线性表的一端开始顺序扫描线性表,依次将扫描到的结点关键字和给定值进行比较。
若当前扫描到的结点关键字与给定值相等,则查找成功;
若扫描结束后,仍未能找到关键字等于给定值的结点,则查找失败。

代码实现如下:
#include <stdio.h>
#include <stdlib.h>

#define MAX 11

typedef int key_type;
typedef struct element
{
	key_type key;	//关键字
}ele;

int seq_search(ele e[], key_type key, int count)
{
	int i = 0;

	while(e[i].key != key && i < count)
	{
		i++;
	}

	if(i < count)
	{
		return(i + 1);
	}
	else
	{
		return -1;
	}

}

int main(int argc, char** argv)
{
	ele linelist[MAX] = {1, 5, 9, 7, 12, 11, 10, 8, 6, 2, 3};

	int count = 11;

	int i = 0;

	key_type key = 8;

	printf("线性表中的元素为:\n");

	while(i < count)
	{
		printf("%d\n", linelist[i].key);
		i++;
	}
	

	printf("\n关键字[%d]在线性表中的位置为[%d]\n", key, seq_search(linelist, key, count));

	system("pause");
	return 0;
}

顺序查找和其他查找算法相比,其缺点是平均查找长度较大,特别当n很大时,其效率非常低。平均查找长度为O(n)。
其优点是:该算法简单且适应面广。它对表的结构无任何要求,无论记录是否按关键字有序。

2.有序表查找(折半查找)

当静态查找表为有序表示,那么可以使用折半查找算法来查找,

折半查找(Binary Search)的查找过程如下:
先确定待查记录所在的范围(区间),然后逐步缩小范围 知道找到或找不到该记录为止。

它对线性表的要求是:关键字值按递增或递减顺序排列。

首先,将要查找的关键字k与中间位置结点的关键字比较,中间结点把线性表分为了两个子表,

若比较结果相等,则查找结束。

若不相等,再根据关键字与该中间结点关键字的 比较结果确定下一步在哪个子表区间内查找。这样递归进行下去。

直到找到满足条件的结点或该线性表中没有这样的结点。

代码实现如下:
#include <stdio.h>
#include <stdlib.h>

#define MAX 12

typedef int key_type;
typedef struct element
{
	key_type key;	//关键字
}ele;

int binary_search(ele* e, key_type key, int count)
{
	int i = -1;
	int low = 0;
	int high = count - 1;
	int mid;

	while(low < high)
	{
		mid = (low + high) / 2;

		if(key < e[mid].key)
			high = mid - 1;
		else if(key > e[mid].key)
			low = mid + 1;
		else
		{
			i = mid;
			break;
		}
	}

	if(i < 0)
		return -1;
	else
		return (i + 1);
}


int main(int argc, char** argv)
{
	ele linelist[MAX] = {3, 5, 6, 8, 9, 12, 17, 23, 30, 35, 39, 42};
	int count = 11;

	int i = 0;

	key_type key = 8;

	printf("线性表中的元素为:\n");

	while(i < count)
	{
		printf("%d\n", linelist[i].key);
		i++;
	}
	

	printf("\n关键字[%d]在线性表中的位置为[%d]\n", key, binary_search(linelist, key, count));

	system("pause");
	return 0;
}
折半查找算法的平均查找长度为O(logn),与顺序查找方法相比,折半查找算法的效率高。速度比顺序查找快。

但折半查找只能使用于有序表,需要对n个元素预先进行排序(仅限于顺序存储结构,对于线性链表无法in性折半查找)。

3. 索引顺序表查找
索引顺序查找,又称分块查找。是顺序查找的一种改进。其性能介于顺序查找和折半查找之间。

分块查找把线性表分成若干块,每一块中的元素存储顺序是任意的,但是块与块之间必须是按关键字大小排序(即前一块中的最大关键字大于(或小于)后一块中的最小(或最大)关键字值)。

另外,需要建立一个索引表,索引表中的一项对应线性表中的一项,索引项由关键字域和链域组成,关键字域存放相应块的最大关键字,链域存放指向本块第一个结点的指针,链域存放指向本块第一个结点的指针,索引表按关键字值递增(或递减)顺序排列。

分块查找的函数分为如下两步:
a)首先确定待查找的结点属于哪一块,即查找所在的块;
b)然后,在块内查找要查的结点。

由于索引表是递增有序的,采用折半查找时,
块内元素个数较少,采用顺序查找在块内查找,

代码实现如下:
#include <stdio.h>
#include <stdlib.h>

#define MAX 16

typedef int key_type;
typedef struct element
{
	key_type key;	//关键字
}ele;

typedef struct _index
{
	key_type key;

	int low, high;
}index;

int index_search(ele* e, key_type key, int count, index *idx, int idx_length)
{
	int i;

	int low = 0;
	int high = idx_length - 1;
	int mid;

	//从块的索引表中查找关键字所在的块(使用折半查找法)
	while(low <= high)
	{
		mid = (low + high) / 2;
		if(key < idx[mid].key)
			high = mid - 1;
		else if(key > idx[mid].key)
			low = mid + 1;
		else
		{
			break;
		}
	}

	//从块中查找关键值(使用顺序查找)
	i = idx[mid].low;
	while(i < idx[mid].high && e[i].key != key)
		i++;

	if(i > idx[mid].high)
		return -1;
	else
		return i + 1;
}

int main(int argc, char** argv)
{
	ele linelist[MAX] = {
		8, 20, 13, 17, 
		
		40, 42, 45, 32,

		49, 58, 50, 52,
		
		67, 79, 78, 80
	};

	int count = sizeof(linelist)/sizeof(ele);
	int i = 0;

	key_type key = 50;

	//建立索引表
	index index_table[4] ={{20,0,3}, {45,4,7}, {58,8,11}, {80,12,15}};
	int idx_length = sizeof(index_table)/sizeof(index);

	printf("线性表中的元素为:\n");

	while(i < count)
	{
		printf("%d\n", linelist[i].key);
		i++;
	}
	

	printf("\n关键字[%d]在线性表中的位置为[%d]\n", key, index_search(linelist, key, count, index_table, idx_length));

	system("pause");
	return 0;
}
存在一问题:如何对给定的数据序列进行分块,本例中是手动进行的分块

索引表查找算法:实际上进行了两次查找(折半查找+顺序查找)。因此整个算法的平均查找长度是两次查找的平均查找长度之和。



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值