データ構造、検索アルゴリズム(バイナリ、ブロック、ハッシュ)

1. 検索アルゴリズム

        1. 二分探索: (前提条件: 順序付けされたシーケンスである必要があります)

#include <stdio.h>
//二分查找 value代表的是被查找的值
int findByHalf(int *p, int n, int value)
{
	int low = 0;//low低
	int high = n-1;//high高
	int middle;//用来保存中间位置的下标
	while(low <= high)//注意此处循环结束的条件,需要加上 =
	{
		//不断获取中间位置的下标
		middle = (low + high) / 2;
		if(value < p[middle])//说明在前半段,移动high
		{
			high = middle-1;
		}
		else if(value > p[middle])//说明在后半段,移动low
		{
			low = middle + 1;
		}
		else//对应p[middle] == value 情况
		{
			return middle;
		}
	}
	return -1;//代表没有找到
}


int main(int argc, const char *argv[])
{
	int a[] = {12,34,56,77,89,342,567,7898};
	int i;
	for(i = 0; i < sizeof(a)/sizeof(a[0]); i++)//把数组中的每个元素都找一遍,进行测试程序
	{
		printf("%d post is %d\n",a[i],findByHalf(a,sizeof(a)/sizeof(a[0]),a[i]));
	}
	//查找10000返回 -1
	printf("%d post is %d\n",10000,findByHalf(a,sizeof(a)/sizeof(a[0]),10000));
	return 0;
}

2. ブロック検索:(ブロック間で順序付け、ブロック内で無秩序)

    インデックステーブル + ソースデータテーブル

    アイデア:

    (1) まずインデックステーブルのどのブロックを決定するか

    (2) 次に、このブロックを横断して検索します。

//インデックステーブル
typedef struct 
{     int max; //ブロック内の最大値     int post;//ブロックの開始位置の添字、ポスト配列の添字}index_t; //インデックス//ソースデータテーブルint a[19] = {18, 10, 9, 8, 16, 20, 38, 42, 19, 50, 84, 72, 56, 55, 76, 100, 90, 88, 108}; 0 5 10 15 //インデックス                              テーブルindex_t b [4] = { {18,0}、{50,5}、{84,10}、{108,15}};



    




#include <stdio.h>
//索引表
typedef  struct 
{
	int max; //块中最大值
	int post;//块的起始位置下标,post数组下标
}index_t; //索引
	
//a原数据表 index_list 索引表 value 被查找的值
int findByBlock(int *a, index_t *index_list,int value)
{
	//start和end作为源数据表的下标取搜索
	int start;//保存起始下标
	int end;//终止下标的后一个位置
	//1.思想,先确定value在哪一块中,遍历索引表与每块中的最大值进行比较
	int i;
	for(i = 0; i < 4; i++)
	{
		if(value <= index_list[i].max)//说明value有可能在i块中
		{
			//确定当前i块中的起始下标和终止
			start = index_list[i].post;
			//假设value在最后一块中,i+1数组越界,所以end的赋值,需要进行条件判断
			if(i == 3)//说明在最后一个块
			{
				end = 19;
			}
			else 
			{
				end = index_list[i+1].post;
			}
			break;//注意此处一定要有break
		}
	}
	//确定块的起点和终点后,对源数据表进行遍历
	for(i = start; i < end; i++)
	{
		if(a[i] == value)
			return i;
	}
	return -1;
}
	

int main(int argc, const char *argv[])
{
	int i;
	//源数据表
	int a[19] = {18, 10, 9, 8, 16, 20, 38, 42, 19, 50, 84, 72, 56, 55, 76, 100, 90, 88, 108};
	//			 0              4  5                   10                  15
	//索引表,结构体数组
	index_t index_list[4] = {
   
   {18,0},{50,5},{84,10},{108,15}};
	for(i = 0; i < 19; i++)//把源数据表中的每一个数据查询一遍,测试程序
	{
		printf("%d post is %d\n",a[i],findByBlock(a,index_list,a[i]));
	}
	printf("%d post is %d\n",22,findByBlock(a,index_list,22));
	
	return 0;
}

3. ハッシュテーブル(ハッシュハッシュ関数)

    ハッシュストレージ

    データ内のキーワードと対応する保存場所の関係を保存するテーブルがあります

    キーを選択する際は、データ内で重複しないキーワードをキーとして選択してください。

    保存する場合は対応関係に従って保存してください

    対応関係に従って取る

####演習 1####

    //セーブデータの年齢+年齢に相当する人口  
    
    10 100
    20 300

    年齢と人口を入力し、対応関係に従ってハッシュテーブルに保存し、
    
    照会する年齢を入力して、その年齢の人口を出力します

 

        3.1 ダイレクトアドレス方式


#include <stdio.h>

//哈希函数,代表了数据中的关键字与存储位置之间的关系
//调用哈希函数能够得到数据的存储位置
int hashFun(int key)
{
	int post = key-1;//key-1代表关系 post通过关系得到存储位置
	return post;
}

//存储数据到哈希表,存的时候按照对应的关系存
void saveAgeNum(int *hash_list,int key,int num)
{
	//1.通过key得到数据存储的位置,调用哈希函数 
	int post = hashFun(key);
	//2.将数据存储到哈希表中
	hash_list[post] = num;
}
//从哈希表中取数据,取的时候按照对应的关系取
int getAgeNum(int *hash_list,int key)
{
	//1.通过key得到数据存储的位置,调用哈希函数 
	int post = hashFun(key);
	//2.将数据取出 
	return hash_list[post];
}
int main(int argc, const char *argv[])
{
	int i;
	int age,num;//年龄和对应年龄的人口数
	int hash_list[200] = { 0 };//哈希表,用来保存年龄和对应年龄的人口数,之所以长度为200,暂定人的寿命为200岁
	for(i = 0; i < 4; i++)
	{
		printf("请您输入年龄和年龄对应的人口数:\n");//输入四组数据保存到哈希表中
		scanf("%d %d",&age,&num);
		//将输入的数据保存到哈希表中
		saveAgeNum(hash_list,age,num);
	}
	//进行查找对应年龄的人口数
	for(i = 0; i < 6; i++)
	{
		printf("请您输入要查询的年龄:\n");
		scanf("%d",&age);
		printf("%d: %d人\n",age,getAgeNum(hash_list,age));
	}
	
	return 0;
}

        3.2 予約剰余方式

    以下のコードデモを参照してください

    データ数はnです

    n = 11

    ハッシュ テーブルの長さ m = n/a //n にはデータの数が格納されます。 a は充填係数で、0.7 ~ 0.8 の間が最も合理的です。

    m = 11 / 0.75 == 15 0 ~ 15 の最大の指数は 13 です。

    //素数はテーブル長以下の素数です

   // 剰余メソッドを保持する

  int hashFun(int key)
    {
        int post = key % prime; //key % 13
        return post;
    }

        3.3 オープンアドレスメソッド//ハッシュストレージ中に生成された競合を解決する

    競合が発生した場合は、ハッシュ関数を使用して配列の添字を取得するのではなく、配列内の空きを見つけてデータを埋めます。

        3.4 競合を解決する方法

                (1) 線形探査法 

#include <stdio.h>
//哈希函数 
int hashFun(int key)
{
	int post = key % 13;//取余13的原因是因为 选不大于哈希表长的最大质数
	return post;
}
//哈希查找
int hashSearch(int *hash_list,int key)
{
	int d = 1;//d 取值 1 2 3 4 5 当冲突发生的时候采用一次线性探查法
	int post;//用来保存存储位置
	int remnum;//用来保存余数
	post = remnum = hashFun(key);
	while(d < 15 && hash_list[post] != 0 && hash_list[post] != key)
	{
		//采用一次线性探查法
		post = (remnum + d) % 15;
		d++;
	}
	if(d >= 15)
		return -1;//代表表已经溢出
	return post;
	//hash_list[post] == 0//意味着当前post这个位置可以存放数据,初始化哈希表所有位置全为0,代表没有存放数据
	//hash_list[post] == key //意味着当前表中的key已经存在
}
//向哈希表中存储数据 
void hashSave(int *hash_list, int key)
{
	//先通过key获取存储位置,对key存储位置进行判断
	int post = hashSearch(hash_list,key);
	if(post == -1 || hash_list[post] == key)
	{
		printf("表溢出或key已经存在!!!\n");
		return;
	}
	//将数据存储到哈希表中 
	hash_list[post] = key;
}

int main(int argc, const char *argv[])
{
	int i;
	int a[11] = {23,34,14,38,46,16,68,15,7,31,26};
	int hash_list[15] = { 0 };//哈希表长度为15 因为 数据长度n / 装填因子a  11 / 0.75,装填因子通常采用0.7-0.8之间最为合理
	//将数据全部保存到哈希表中
	for(i = 0; i < 11; i++)
	{
		hashSave(hash_list,a[i]);
	}
	//打印哈希表 
	for(i = 0; i < 15; i++)
	{
		printf("%d ",hash_list[i]);
	}
	printf("\n");
	return 0;
}

        (2) チェーンアドレス方式 

#include <stdio.h>
#include <stdlib.h>

typedef struct node_t  
{
	int key;
	struct node_t *next;
}link_node_t,*link_list_t;

//哈希函数
int hashFun(int key)
{
	int post = key % 13;
	return post;
}

link_list_t hashSearch(link_list_t *hash_list,int key)
{
	link_list_t h = NULL;//用来保存无头链表的头指针
	//1.先通过key调用哈希函数获取位置
	int post = hashFun(key);//需要将判断key放入第条链表
	h = hash_list[post];//h指向key对应存储位置的那条链表
	while(h != NULL && h->key != key)//相当于遍历无头链表,同时检查key
	{
		h = h->next;
	}
	return h;
	//h == NULL 说明没找到key可以进行存储
	//h != NULL h->key == key 说明key已经存在
}

//存储数据
void hashSave(link_list_t *hash_list,int key)
{
	int post = hashFun(key);
	link_list_t pnew = NULL;//用来保存新创建的节点
	link_list_t p = hashSearch(hash_list,key);
	if(p == NULL)//key不存在,可以进行插入数据
	{
		//1.创建一个新的节点用来保存key 
		pnew = (link_list_t)malloc(sizeof(link_node_t));
		if(NULL == pnew)
		{
			perror("pnew malloc failed");
			return;
		}
		//2.将key保存到新节点中
		pnew->key = key;
		pnew->next = NULL;
		//3.将新的节点插入到对应存储位置的链表中,将新节点每次插入无头链表头的位置
		pnew->next = hash_list[post];
		hash_list[post] = pnew;
	}
	else
	{
		printf("key已经存在了!!!\n");
	}
}


int main(int argc, const char *argv[])
{
	int i;
	link_list_t h = NULL;//临时保存每条链表的头
	int a[11] = {23,34,14,38,46,16,68,15,7,31,26};	
	//hash_list是一个结构体指针数组,每一个元素都是结构体指针
	link_list_t hash_list[13] = { 0 };//为什么长度是13,因为保留余数法每次%13 得到的位置在0-12之间
	//将所有的key保存起来
	for(i = 0; i < 11; i++)
	{
		hashSave(hash_list,a[i]);
	}
	//遍历哈希表 有13条链表
	for(i = 0; i < 13; i++)//hash_list中保存的是13条无头链表的头指针
	{
		printf("%d:",i);
		h = hash_list[i];
		while(h != NULL)//相当于遍历无头链表
		{
			printf("%d ",h->key);
			h = h->next;
		}
		printf("\n");
	}
	return 0;
}

おすすめ

転載: blog.csdn.net/qq_52119661/article/details/132437554