五十九、部分的排序与查找
- 回头找个时间单独搞一个排序查找的文章,这个就先水一水
59.1 直接插入排序
- 在给出的序列中,假定一个已经排好序的序列,不断把后面的元素插入到该序列中,并排序
- 思想: 从第二个元素开始,每个元素都逐个向前比较,如果找到它该待的地方(看升序还是降序,升序就是某个位置的前面比这个元素小,后面比这个元素大),那就将这个元素插入到这个位置上
59.1.1 直接插入排序的功能代码
void insert_sort(int *arr, int len)
{
for (int i = 1, j; i < len; i++)
{
int temp = arr[i];
for (j = i; j > 0 && arr[j - 1] > temp; j--)
{
arr[j] = arr[j - 1];
}
arr[j] = temp;
}
}
59.1.2 完整代码示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void insert_sort(int *arr, int len)
{
for (int i = 1, j; i < len; i++)
{
int temp = arr[i];
for (j = i; j > 0 && arr[j - 1] > temp; j--)
{
arr[j] = arr[j - 1];
}
arr[j] = temp;
}
}
int main(int argc, const char *argv[])
{
int arr[] = {2, 3, 5, 4, 7, 5, 1, 2};
int len = sizeof(arr) / sizeof(arr[0]);
insert_sort(arr, len);
for (size_t i = 0; i < len; i++)
{
printf("%d\n", arr[i]);
}
return 0;
}
59.2 哈希查找
- 查找就是在一大堆东西里面找到想要的东西,应该不会有人不知道吧???
- 不会吧?!
- 不会吧?!
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/c51bd0ebf18b5190ca91ba9945692d11.png)
59.2.1 常用的处理冲突方法
- 开放定址法
- 线性探测法:往后逐个找空位,找到第一个空位坐下
- 二次探测法:往后按加1/4/9/16/25/36…这种方式找,比如下一位,下第四位之类,这些数是1/2/3/4/5/6…的二次方
- 伪随机探测法:百度去,字太多了,不想写
- 再哈希法:再次取模,不过模的数应该会变,具体看需求
- 链地址法:每个位置变成链表,相同位置的都在同一个链表里面
- 建立公共溢出区:将哈希表分为公共表和溢出表,当溢出发生时,将所有溢出数据统一放到溢出区
59.2.1 链地址法
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/627ec90647ad17ea8fbb7508b3193709.png)
59.2.2 哈希表的表长
- 哈希表的长度:关键字的个数/0.75 ====>取最大素数
- 关键字的个数 * 4/3
59.2.3 哈希表的结构体
#define LEN 10
#define MAX 13
typedef struct myhash
{
int key;
struct myhash *next;
} hash;
59.2.4 哈希表初始化
hash **hash_init()
{
hash **h = (hash **)malloc(sizeof(hash *) * MAX);
if (NULL == h)
{
printf("哈希表初始化失败\n");
return NULL;
}
for (int i = 0; i < MAX - 1; i++)
{
*(h + i) = NULL;
}
return h;
}
59.2.5 创建关键字结点
hash *creat_node(int value)
{
hash *node = (hash *)malloc(sizeof(hash));
if (NULL == node)
{
printf("关键字结点创建失败\n");
return NULL;
}
node->key = value;
node->next = NULL;
return node;
}
59.2.6 向哈希表中存放关键字
void save_key(hash **h, int value)
{
if (NULL == h)
{
printf("存关键字时入参为空\n");
return;
}
int index = value % MAX;
hash *node = creat_node(value);
node->next = h[index];
h[index] = node;
}
59.2.7 在哈希表中查找数据
int search_hash(hash **h, int data)
{
if (NULL == h)
{
printf("查找数据时入参为空\n");
return -1;
}
int index = data % MAX, i = 1;
hash *node = h[index];
while (NULL != node)
{
if (data == node->key)
{
printf("\n%d在哈希表的H[%d]链表中第%d个\n", data, index, i);
return index;
}
++i;
node = node->next;
}
printf("找不到 %d 这个数据\n", data);
return -1;
}
59.2.8 遍历输出哈希表
void out_hash(hash **h)
{
if (NULL == h)
{
printf("遍历输出时入参为空\n");
return;
}
for (int i = 0; i < MAX; i++)
{
hash *p = h[i];
printf("H[%-2d]:", i);
while (NULL != p)
{
printf("%d-->", p->key);
p = p->next;
}
puts("");
}
}
59.2.9 销毁哈希表
void free_hash(hash ***h)
{
if (NULL == h)
{
printf("销毁哈希表时入参为空\n");
return;
}
for (int i = 0; i < MAX; i++)
{
puts("");
hash *p = (*h)[i];
while (NULL != p)
{
hash *q = p;
p = p->next;
printf("%7d已被释放\n", q->key);
free(q);
}
printf("H[%-2d]已被释放完\n", i);
}
free(*h);
*h = NULL;
}
59.3 哈希表实现的完整代码(接口,功能实现,测试用主函数,Makefile)
接口(hash.h)
#ifndef __HASH_H__
#define __HASH_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 10
#define MAX 13
typedef struct myhash
{
int key;
struct myhash *next;
} hash;
hash **hash_init();
hash *creat_node(int value);
void save_key(hash **h, int value);
int search_hash(hash **h, int data);
void out_hash(hash **h);
void free_hash(hash ***h);
#endif
功能实现(hash.c)
#include "hash.h"
hash **hash_init()
{
hash **h = (hash **)malloc(sizeof(hash *) * MAX);
if (NULL == h)
{
printf("哈希表初始化失败\n");
return NULL;
}
for (int i = 0; i < MAX - 1; i++)
{
*(h + i) = NULL;
}
return h;
}
hash *creat_node(int value)
{
hash *node = (hash *)malloc(sizeof(hash));
if (NULL == node)
{
printf("关键字结点创建失败\n");
return NULL;
}
node->key = value;
node->next = NULL;
return node;
}
void save_key(hash **h, int value)
{
if (NULL == h)
{
printf("存关键字时入参为空\n");
return;
}
int index = value % MAX;
hash *node = creat_node(value);
node->next = h[index];
h[index] = node;
}
int search_hash(hash **h, int data)
{
if (NULL == h)
{
printf("查找数据时入参为空\n");
return -1;
}
int index = data % MAX, i = 1;
hash *node = h[index];
while (NULL != node)
{
if (data == node->key)
{
printf("\n%d在哈希表的H[%d]链表中第%d个\n", data, index, i);
return index;
}
++i;
node = node->next;
}
printf("找不到 %d 这个数据\n", data);
return -1;
}
void out_hash(hash **h)
{
if (NULL == h)
{
printf("遍历输出时入参为空\n");
return;
}
for (int i = 0; i < MAX; i++)
{
hash *p = h[i];
printf("H[%-2d]:", i);
while (NULL != p)
{
printf("%d-->", p->key);
p = p->next;
}
puts("");
}
}
void free_hash(hash ***h)
{
if (NULL == h)
{
printf("销毁哈希表时入参为空\n");
return;
}
for (int i = 0; i < MAX; i++)
{
puts("");
hash *p = (*h)[i];
while (NULL != p)
{
hash *q = p;
p = p->next;
printf("%7d已被释放\n", q->key);
free(q);
}
printf("H[%-2d]已被释放完\n", i);
}
free(*h);
*h = NULL;
}
测试用主函数(main.c)
#include "hash.h"
int main(int argc, char const *argv[])
{
hash **H = hash_init();
int arr[LEN] = {25, 51, 8, 22, 26, 67, 11, 16, 54, 41};
for (int i = 0; i < LEN; i++)
{
save_key(H, arr[i]);
}
out_hash(H);
int ret = search_hash(H, 67);
printf("%d\n", ret);
int ret2 = search_hash(H, 66);
printf("%d\n", ret2);
free_hash(&H);
printf("\nH=%p\n", H);
return 0;
}
makefile
EXE=hash
CC=gcc
CFLAGs=-c
OBJs+=main.o
OBJs+=hash.o
all=$(EXE)
$(EXE):$(OBJs)
$(CC) $^ -o $@
%.o:%.c
$(CC) $(CFLAGs) $^ -o $@
clean:
rm *.o hash
59.4 折半查找
- 折半查找,一定是对 有序序列 的查找
- 每次查找都能将范围缩小一半
- 从有序序列的中间开始,如果中间的值比待查找数据的值大,那就去低半边查,反之去高半边
59.4.1 折半查找的功能函数代码
int half_search(int *a, int low, int high, int value)
{
int mid;
while (low <= high)
{
mid = (low + high) / 2;
if (a[mid] == value)
{
printf("找到了\n");
return mid;
}
else if (a[mid] > value)
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}
printf("没找到\n");
return -1;
}
59.4.2 完整代码示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int half_search(int *a, int low, int high, int value);
int main(int argc, const char *argv[])
{
int arr[] = {1, 2, 3, 4, 6, 7, 8};
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = len - 1; i >= 0; i--)
{
printf("%d\n", half_search(arr, 0, len - 1, arr[i]));
}
printf("%d\n", half_search(arr, 0, len - 1, 90));
return 0;
}
int half_search(int *a, int low, int high, int value)
{
int mid;
while (low <= high)
{
mid = (low + high) / 2;
if (a[mid] == value)
{
printf("找到了\n");
return mid;
}
else if (a[mid] > value)
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}
printf("没找到\n");
return -1;
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/9aa5be7e26a5ded8c84dca903641006e.png)