一.查找相关概念
这一部分解释数据结构里面查找的相关基础概念:
- 查找:在数据集合中寻找满足某种条件的数据元素的过程。
- 查找表:用于查找的数据集合
- 关键字:数据元素中唯一标识该元素的某个数据项的值
- 静态查找表:静态查找表是指在查找表建立后,查找表中的元素不再发生变化。
- 动态查找表:动态查找表是指在查找表建立后,查找表中的元素可能会发生增加、删除等变化。
- 查找长度:查找长度是指在进行一次查找操作时,需要比较的关键字的个数
- 平均查找长度:平均查找长度是指进行n次查找操作时,所有查找长度之和除以n的结果。
二.顺序查找(线性查找)
1.对象
- 静态查找表
- 线性表(顺序表、链表)
2.原理
从数据结构的起始位置开始,依次检查每个元素,直到找到目标元素或到达数据结构的末尾为止。
具体步骤如下:
- 从数据结构的第一个元素开始遍历,依次和目标元素进行比较。
- 如果当前元素等于目标元素,则返回该元素位置。
- 如果已经遍历完所有元素(即到达数据结构的末尾)仍未找到目标元素,则返回查找失败。
顺序查找的时间复杂度为O(n),其中n为数据结构中元素的数量。当数据量较小或者数据结构没有特定的有序性质时,顺序查找是一个常用的查找方法。
3.代码
typedef struct{ //查找表的数据结构(顺序表) ElemType *elem; //动态数组基址 int TableLen; //表的长度 }SSTable; //顺序查找 int Search_ _Seq(SSTable ST, ElemType key){ int i; for( i=0;i<ST. TableLen)&& ST.elem[i] !=key; ++i); //查找成功,则返回元素下标;查找失败,则返回-1 return i==ST.TableLen? (-1): i; }
三.折半查找(二分查找)
1.对象
- 静态查找表
- 有序的顺序表
2.原理
它的原理基于以下思想:
- 首先确定待查找区间的左右端点 mid、left 和 right,并计算出中间位置 mid。
- 将要查找的值与 mid 位置上的元素进行比较。如果相等,则返回 mid;否则,判断查找值与 mid
- 元素大小的关系,若小于 mid 位置的元素,则在左侧区间继续查找;否则,在右侧区间继续查找。
- 不断重复以上操作,直到找到目标元素或者区间为空。
具体地,折半查找的实现步骤如下:
初始化 left 和 right 为数组的左右端点,即 left=0,right=n-1,其中 n 表示数组的长度。
计算 mid 位置,即 mid = (left + right) / 2。
判断查找值是否等于 mid 位置上的元素,如果是,则返回 mid。如果不是,则比较查找值和 mid
- 位置上的元素大小关系,如果小于 mid 位置上的元素,则从 left 到 mid - 1 的区间内继续查找;否则,从 mid + 1 到 right 的区间内继续查找。
- 重复步骤 2 和 3,直到找到目标元素或者区间为空。
需要注意的是,折半查找只适用于有序数组。如果数组没有排序,则需要先对数组进行排序。
折半查找(二分查找)的时间复杂度是 O(log n)。
3.代码
typedef struct{ //查找表的数据结构(顺序表) ElemType *elem; //动态数组基址 int TableLen; //表的长度 }SSTable; //折半查找 int Binary_ Search(SSTable L, ElemType key){ int Low=0, high=L.TableLen-1,mid; while(low<=high){ mid=(low+high)/2; //取中间位置 if(L.elem [mid]==key) return mid; //查找成功则返回所在位置 else if(L.elem[mid]>key) high=mid-1; //从前半部分继续查找 else low=mid+1; //从后半部分继续查找 } return - 1; //查找失败,返回-1 }
四.分块查找(索引顺序查找)
1.思想
它的基本思想是将有序表分成若干个块,每个块中存储多个关键字,并且块之间按照关键字的大小顺序连接起来。这样就形成了一个“块链”。
在进行查找时,先在块中进行二分查找,如果找到了关键字,则返回;若未找到,则需要在相邻的块中继续查找。由于块之间是有序的,因此可以采用类似于二分查找的方法来确定需要进入哪个块中进行查找,从而可以减少查找的次数,提高查找效率。
分块查找的时间复杂度为 O(√n),其中 n 表示有序表中元素的个数。虽然它的效率不如二分查找,但是在某些特定情况下,如查找次数较少、表比较大等情况下,分块查找仍然具有一定的优势。
2.C语言模拟分块查找
int blockSearch(int arr[], int n, int x, int blockSize) { // 计算块数 int blocks = (int)ceil((double)n / blockSize); // 数组 index 表示每个块的起始下标,maxIndex 表示当前块中最大的下标 int index[blocks], maxIndex[blocks]; for (int i = 0; i < blocks; i++) { index[i] = i * blockSize; maxIndex[i] = (i + 1) * blockSize - 1; if (maxIndex[i] >= n) { maxIndex[i] = n - 1; } } // 查找所在块 int block = -1; for (int i = 0; i < blocks; i++) { if (arr[index[i]] <= x && arr[maxIndex[i]] >= x) { block = i; break; } } // 块内顺序查找 if (block == -1) { return -1; } for (int i = index[block]; i <= maxIndex[block]; i++) { if (arr[i] == x) { return i; } } return -1; }
五.总结
这里我们学习路顺序查找、折半查找、分块查找,一定要注意它们各自使用的对象和方法。
这里本来是想写一下哈希函数的,想了想还是留在散列查找的时候再写。
六.说明
新星计划:数据结构与算法,@西安第一深情,创作打卡2!