一.分块查找思路
前言:二分查找是每次从中间开始找数据,每次都砍掉数据的一半使数据的时间复杂度降低
背景:在使用分块查找时,大家一定都会用二分查找法,在二分查找法中数据必须为有顺序,但是排序本身是一个很耗费时间的事情(数据本身没有顺序/数据很难排序),所以就有了分块查找,这是一种不需要严格有序而且可以提高效率的一种算法;
例子:例如一本书的目录,查字典(可能比较抽象)
也就是说不需要大量严格的排序,就可以在所属分块中找到数据
二.代码实现
(1)创建随机字符串并且让随机字符串存入“块”
// 数据规模: 100万
#define SCALE 1000*1000 // 字符串总数
#define MAXLEN 20 // 字符串最大长度
/**
* @brief 生成随机字符串
*
* @return char*
*/
char *random_string()
{
int len = rand()%20;
len = ((len < 2) ? 2 : len);//做一个先幅,让len:2~19
char *s = calloc(1, len);//分配字符串的堆内存
char letter[] = {'a', 'A'};
for(int i = 0; i < len - 1; i ++)
{
s[i] = letter[rand() % 2] + (rand() % 26);//随机字符
}
return s;
}
void create_index(char data[][MAXLEN], int **index)
{
//统计所有字符出现的次数
int n[52] = {0};
for(int k = 0; k < SCALE; k++)
{
//让小写字符为0~25,大写字符为26~51
int pos = ((data[k][0]) >= 'a') ? (data[k][0] - 'a') : (data[k][0]-'A' + 26);
n[pos] ++;
}
for(int i = 0; i < 52; i++)
{
//给index分配内存总个数+1是因为每个数都要有记录整个数量的头
index[i] = calloc(n[i] + 1, sizeof(int));
}
//找见开头为‘字符’的下表并存入
for(int i = 0; i < SCALE; i++)
{
int pos = ((data[i][0] >= 'a') ? (data[i][0]-'a') : (data[i][0]-'A'+26));
int k = ++index[pos][0];
index[pos][k] = i;
}
}
void store(char data[][MAXLEN], const char *file)
{
FILE *fp = fopen(file, "w");
for(int i=0; i<SCALE; i++)
fprintf(fp, "%06d.%s\n", i, data[i]); // 数据规模:100万(6位数)
fclose(fp);
}
(2)查找实现
int main(void)
{
// 1. 产生随机字符串数据集
// 假设每个字符串长度不超过MAXLEN个字符
char (*data)[MAXLEN] = calloc(SCALE, MAXLEN);
srand(time(NULL));
for(int i=0; i<SCALE; i++)
{
char *s = random_string();
strncpy(data[i], s, strlen(s));
free(s);
}
store(data, "a.txt");
// 2. 按首字母建立索引(分块)
int **index = calloc(52, sizeof(int *));
create_index(data, index);
// 3. 利用索引,进行查找
char str[32];
printf("请输入你要查找的字符串:\n");
while(1)
{
// 从键盘接收一个待查找的字符串并去掉回车符
bzero(str, 32);//用于清零原来输入的字符串
fgets(str, 32, stdin);
strtok(str, "\n");
bool done = false;
for(int i=1; i<SCALE; i++)
{
// 小写字母[00~25],大写字母[26~51]
int pos = ((str[0]>='a') ? (str[0]-'a') : (str[0]-'A'+26));
count++;
if(i<=index[pos][0] && strcmp(data[index[pos][i]], str) == 0)
{
printf("你要找的字符串在第%d行", index[pos][i]);
done = true;
break;
}
else if(i > index[pos][0])
break;
}
if(!done)
printf("没有你要的字符串");
printf("【找了%d次】\n", count);
count=0;
}
return 0;
}