• 四种静态查找方法(c代码解析)



    静态查找指的是只对表执行查找操作,并不会动态添加元素

    顺序查找

    无序的序列中使用顺序查找,查找速度是最慢的。

    在顺序 {1,2,3,4,5,6,7,8,9}中查找5元素的位置 :

    int 顺序查找(int* s, int n, int k)
    {
    	int Idx = 0;
    	while (Idx < n && s[Idx] != k)
    	{
    		Idx++;
    	}
    	if (Idx >= n)
    	{
    		return 0;		//未找到返回0
    	}
    	else
    	{
    		return Idx + 1;	//返回其物理位置
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    二分查找

    有序的序列中使用二分查找,二分查找的速度是静态查找中最快的,

    
    int 二分查找(int* arr, int n, int k)
    {
    	int left = 0, right = n - 1;
    	while (left <= right)
    	{
    		int mid = left + (right - left) / 2;
    		if (arr[mid] < k)
    		{
    			left = mid + 1;
    			
    		}
    		else if (arr[mid] > k)
    		{
    			right = mid - 1;
    		}
    		else
    		{
    			return mid + 1;//返回其物理位序
    		}
    	}
    	return 0;	//没有找到返回0
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    索引查找

    索引查找的查找过程:首先在索引表中查找关键字 key 对应的位置,然后根据这个位置可以获得此位置对应的序号,此序号就是对应主数据表的索引

    索引表pos:

    地址索引关键字对应的序号
    02021011
    12021032
    22021050

    主数据表Main:

    地址关键字其他数据信息
    0202105
    1202101
    2202103

    注意:索引表的索引关键字最好是有序的,我们可以在索引表中使用 二分查找

    例如,查找 202103 对应的学生:

    • 通过索引表查找 202103,利用二分查找,找到之后,它所对应的序号2,就是主数据表对应此项的索引下标。
    
    //主数据表
    typedef struct
    {
    	std::string name;
    	int age;
    	int num;
    }MainTable;
    
    //索引表
    typedef struct
    {
    	KeyType key;	//用于查找的关键字
    	int pos;		//关键字元素在主数据表中的索引
    }PosTable;
    int 索引查找(PosTable c[], int n, int k)
    {
    	int left = 0, right = n - 1;
    	while (left <= right)
    	{
    		int mid = left + (right - left) / 2;
    		if (c[mid].key > k)
    		{
    			right = mid - 1;
    		}
    		else if (c[mid].key < k)
    		{
    			left = mid + 1;
    		}
    		else
    		{
    			return c[mid].pos + 1;	//根据索引表的地址得到对应数据表的序号,并返回逻辑序号
    		}
    	}
    	return 0;	//没有找到
    }
    int main()
    {
    	MainTable student[] = { {"张三",18,202101},{"李四",19,202103},{"赵六",25,202105},{"王五",23,202104},{"刘八",21,202107} };
    	PosTable pos[] = { {202101,0},{202103,1},{202104,3},{202105,2},{202107,4} };
    	int Idx = 索引查找(pos, 5, 202107);	// 5
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    分块查找

    思路: 把主数据表的元素分成若干块,每一块的元素可以是无序或者有序的,但是块与块之间的元素一定是有序的,块有一个单独的关键字,前一个块的关键字必须大于(小于)后一个块的关键字。

    typedef struct{
    	int key;	//块关键字
    	int low;	//块内最小下标
    	int high;	//块内最大下标
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    数据: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

    1. 把他们分块:[1 2 3 4] [5 6 7 8] [9 10 11 12] [13 14 15 16] [17 18 19 20],一共有五个块。

    2. 每一块都具有关键字(用于查找),low和high来存储这一块内的最小和最大下标

    关键字lowhigh
    403
    847
    12811
    161215
    201619
    1. 把每一块的关键字当作一组数,二分查找块关键字(4,8,12,16,20),当查找到了一个数字大于前一个块,并且小于后一个块,转而到块内寻找此数据(如16: 12,13,14,15)。
    //块数
    #define K_NUM 4
    
    
    
    void 分块(int* arr,int n,*& kuai)
    {
    	//20个元素,可以分4块,每块5个元素
    	int num_每块的元素 = 20 / K_NUM;	 
    	int num = 1;	//每遍历n个元素,换一个块
    	int kIdx = 0;	//每块下标
    	int max_value = 0;
    	for (int i = 0; i < n; i++)
    	{
    		//寻找每一块的最大值
    		max_value = max(arr[i], max_value);
    		if (num == 1)
    		{
    			kuai[kIdx].low = i;			//一开始,最小下标保存
    			num++;
    		}
    		else if (num == num_每块的元素)
    		{
    			kuai[kIdx].high = i;		//结束时,最大下标保存
    			kuai[kIdx].key = max_value;	//关键字保存块中,为块内最大的元素
    			num = 1;					//为下一个块做准备,重新开始
    			kIdx++;						//到下一个块
    		}
    		else
    		{
    			num++;
    		}
    	}
    }
    
    int 二分查找_块(int* arr, 块 k[], int n_kuai, int val)
    {
    	int left = 0, right = n_kuai - 1;
    	int mid = 0;
    	while (left <= right)
    	{
    		mid = left + (right - left) / 2;
    		if (val <= k[mid].key)
    		{
    			right = mid - 1;
    		}
    		else
    		{
    			left = mid + 1;
    		}
    	}
    	//在某块内查找
    	int Idx = k[right+1].low;
    	while (Idx <= k[right + 1].high && arr[Idx] != val)
    	{
    		Idx++;
    	}
    	if (Idx <= k[right + 1].high)
    	{
    		return Idx + 1;	//返回逻辑位序
    	}
    	else
    	{
    		return 0;		//没有找到,返回零
    	}
    }
    
    int main()
    {
        int arr[20] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 };* k = new[K_NUM]{};
        //1. 数据分块
    	分块(arr, 20, k)
    	//2. 二分查找块,并且在块内寻找数据
    	for (int i = 20; i >= -5; i--)
    	{
    		int Idx =  二分查找_块(arr, k, 4, i);
    		printf("%d ", Idx);	// 20 19 18 17 16 ......2 1 0 0 0 0 0 
    	}
    	delete[] k;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
  • 相关阅读:
    C/C++ 实现Windows注册表操作
    C++设计模式——单例模式
    精通Nginx(08)-反向代理
    方法递归调用
    【跟小嘉学 Rust 编程】二十四、内联汇编(inline assembly)
    【数据结构】图(Graph)
    ElasticSearch-全文检索快速入门
    05 Spring整合MyBatis
    身份证扩展(类构造与析构)Java
    THREE--demo10(地球坐标)
  • 原文地址:https://blog.csdn.net/jj6666djdbbd/article/details/127811052