数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。
目录
1.查找的基本概念
为了便于对后面各节对各种查找算法的比较,首先介绍以下查找的概念和术语。
(1)查找表
查找表是由同一类型的数据元素(或记录)构成的集合。由于“集合”中的数据元素之间存在着完全松散的关系,因此查找表是一种非常灵便的数据结构,可以利用其他的数据结构来实现,比如本章将要介绍的线性表、树表及散列表等。
(2)关键字
关键字是数据元素(或记录)中某个数据项的值,用它可以标识一个数据元素(或记录)。若此关键字可以唯一的标识一个记录,则称此关键字为主关键字(对不同的记录,其主关键字均不同)。反之,称用以识别若干记录的关键字为次关键字。当数据元素只有一个数据项是,其关键字即该数据元素的值。
(3)查找
查找是根据给定的某个值,在查找表中确定一个其关键字等于给定值的记录或数据元素。若表中存在这样一个记录,则称查找成功,此时查找的结果可给出整个记录的信息,或指示该记录在查找表中的位置;若表中不存在关键字等于给定值的记录,则称查找不成功,此时查找的结果可给出一个“空”记录或“空”指针。
(4)动态查找表和静态查找表
若在查找的同时对表执行修改操作(如插入或删除),则称相应的表为动态查找表,否则称之为静态查找表。换句话说,动态查找表的表结构本身是在查找过程中动态生成的,即在创建表时,对于给定值,若表中存在其关键字等于给定值的记录,则查找成功并返回;否则插入关键字等于给定值的记录。
(5)平均查找长度
为确定记录在查找表中的位置,需和给定值进行比较的关键字个数的期望值,称之为查找算法在查找成功时的平均查找长度。
2.线性表的查找
1.顺序查找
顺序查找的查找过程为:从表的一端开始,依次将记录的关键字和给定值进行比较,若某个记录的关键字和给定值相等,则查找成功;反之,若查找整个表后,仍未找到关键字和给定值相等的记录,则查找失败。
顺序查找方法即适用于线性表顺序存储结构,又适用于线性表的链式存储结构。下面只介绍以顺序表作为存储结构时的插找算法,以下为代码部分
代码段我们选用C#进行讲解,为了更好的迎合教材以及讲解性,我们使用大量的替换符,以下为头文件以及替换符部分。
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int ElemType;
然后就是创建顺序表以及输入顺序表内容的部分。
typedef struct {
ElemType *elem; //指向数据元素的基地址
int length; //线性表的当前长度
}SqList;
Status CreateSTable(SqList *L,int n)
{
L->elem=(int*)malloc(sizeof(int)*MAXSIZE);
if(!L->elem) exit(OVERFLOW);
L->length=n+1;
for(int i=1;i<L->length;i++){
scanf("%d",&L->elem[i]);
}
return OK;
}
接下来就是核心的查找部分,由于是顺序查找,较为基础所以代码段比较简单。不再过多赘述
Status Search_Seq(SqList L,int n){
L.elem[0]=n;
for(int i=1;i<=L.length;i++){
if(L.elem[0]==L.elem[i]){
return i;
}
}
return OK;
}
最后是主函数部分。
int main()
{
SqList L;
int n,n1;
//提示:输入元素个数:
scanf("%d",&n);
CreateSTable(&L,n);
// printf("输入待查记录的关键字:\n");
scanf("%d",&n1);
// printf("程序输出计算的位置为:\n");
printf("%d",Search_Seq(L,n1));
return 0;
}
2.顺序查找的优缺点
顺序查找的特点:算法简单,对表结构无任何要求,即适用于顺序结构,也适用于链式结构,无论记录是否按关键字有序均可应用。其缺点是:平均查找长度较大,查找效率较低,所以当基数过大时,不建议使用顺序查找。
3.折半查找
折半查找也称二分查找,它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。在下面及后续的讨论中,均假设有序表是有序递增的。
折半查找的查找过程为:从表的中间记录开始,如果给定值和中间记录的关键字相等,则查找成功;如果给定值小于或者大于中间记录的关键字,则在表中大于或小于中间记录的那一半查找,这样重复操作,直到查找成功,或者在某一步中查找区间为空,则代表查找失败。
折半查找每一次都使查找范围缩小一半,与顺序查找相比,很显然会提高查找效率。
为了标记查找过程中每一次的查找区间,下面分别用low和high来表示当前区间的上界和下界,mid为区间的中间位置。以下为代码段。
代码段我们选用C#进行讲解,为了更好的迎合教材以及讲解性,我们使用大量的替换符,以下为头文件以及替换符部分。
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int ElemType;
然后就是创建顺序表以及输入顺序表内容的部分。
typedef struct {
ElemType *elem; //指向数据元素的基地址
int length; //线性表的当前长度
} SqList;
Status CreateSTable(SqList *L, int n) {
L->elem = (int*)malloc(sizeof(int) * MAXSIZE);
if (!L->elem) exit(OVERFLOW);
L->length = n + 1;
for (int i = 1; i < L->length; i++) {
scanf("%d", &L->elem[i]);
}
return OK;
}
然后就是折半查找部分,这里中间值用mid定义,最大值和最小值分别定义为high和low。
void sort(SqList *L) {
for (int i = 1; i < L->length; i++) {
for (int j = 1; j < L->length - 1 - i; j++) {
if (L->elem[j] > L->elem[j + 1]) {
L->elem[0] = L->elem[j + 1];
L->elem[j + 1] = L->elem[j];
L->elem[j] = L->elem[0];
}
}
}
}
Status Search_Bin(SqList L, int n1, int high, int low) {
int mid = (low + high) / 2;
if (L.elem[mid] < n1) {
low = mid + 1;
} else if (L.elem[mid] > n1) {
high = mid - 1;
} else {
return mid;
}
Search_Bin(L, n1, high, low);
}
最后是主函数部分。其中包含部分输入过程。
int main() {
SqList L;
int n, n1, low, high;
scanf("%d", &n);
CreateSTable(&L, n);
sort(&L);
scanf("%d", &n1);
low = 1;
high = L.length - 1;
printf("%d",Search_Bin(L, n1, high, low));
return 0;
}
4.折半查找的优缺点:
折半查找的特点是:比较次数少,查找效率高。其缺点是:对表结构要求高,只能用于顺序存储的有序表。采用折半查找前元素需要排序,而排序本身是一种费时运算。同时为了保持顺序表的有序性,对有序表进行插入和删除时,平均比较和移动表中一半元素,这也是一种费时的运算。因此,折半查找不适用于数据元素经常变动的线性表。
2.小总结
本次内容主要了讲解了数据结构中的一些基础知识点,主要内容顺序表的有关知识本篇内容都为数据结构的基本思想,若想更深的理解以及体会,还请大家在日常学习中多多努力,希望大家学有所成。