C++ 数据结构算法 学习笔记(33) -查找算法及企业级应用

C++ 数据结构算法 学习笔记(33) -查找算法及企业级应用

数组和索引

日常生活中,我们经常会在电话号码簿中查阅“某人”的电话号码,按姓查询或者按字母排 序查询;在字典中查阅“某个词”的读音和含义等等。在这里,“电话号码簿”和“字典”都可 看作一张查找表,而按“姓”或者“字母”查询则是按索引查询!

在这里插入图片描述

索引把线性表分成若干块,每一块中的元素存储顺序是任意的,但是块与块间必须按关键字 大小按顺序排列。即前一块中的最大关键字值小于后一块中的最小关键字值。 分块以后,为了快速定义块,还需要建立一个索引表,索引表中的一项对应于线性表中的一 块,索引项由键域和链域组成。键域存放相应关键字的键值,链域存放指向本块第一个节点和最 后一个节点的指针,索引表按关键字由小到大的顺序排列!

数组是特殊的块索引(一个块一个元素):

在这里插入图片描述

哈希表是非常经典的块索引!

在这里插入图片描述

分块查找的算法分两步进行,首先确定所查找的节点属于哪一块,即在索引表中查找其所在的块, 然后在块内查找待查询的数据。由于索引表是递增有序的,可采用二分查找,而块内元素是无序 的,只能采用顺序查找。(块内元素较少,则不会对执行速度有太大的影响

二分查找

二分查找法实质上是不断地将有序数据集进行对半分割,并检查每个分区的中间元素。再重 复根据中间数确定目标范围并递归实行对半分割,直到中间数等于待查找的值或是目标数不在搜 索范围之内!

#include <iostream>
#include <string>

using namespace std;

int int_compare(const void* key1, const void* key2)
{
	const int* ch1 = (const int*) key1;
	const int* ch2 = (const int*) key2;

	return (*ch1 - *ch2);
}


int char_compare(const void* key1, const void* key2)
{
	const char* ch1 = (const char*)key1;
	const char* ch2 = (const char*)key2;

	return (*ch1 - *ch2);
}

int BinarySearch(void* sorted, int len, int elemSize, void* search, int (*compare)(const void *key1, const void *key2))
{
	int left = 0; 
	int right = 0;
	int middle = 0;

	left = 0;
	right = len - 1;

	while (left <= right)
	{
		int ret = 0;
		middle = (left + right) / 2;
		ret = compare(static_cast<char *>(sorted)+(elemSize*middle), search);
		if (ret ==0)
		{
			return middle;
		}
		else if (ret >0)
		{
			right = middle - 1;
		}
		else
		{
			left = middle + 1;

		}
	}
	return -1;
}

int main()
{ 
	int arr[] = { 1,3,7,9,11 };
	int search[] = {0,1,7,2,11,12};
	for (int i = 0; i < sizeof(search) / sizeof(search[0]); i++)
	{
		int index = BinarySearch(arr, sizeof(arr) / sizeof(arr[0]),sizeof(int), & search[i], &int_compare);
		cout << "The result is: " << index << endl;
	}

	char arr1[] = { 'a','c','d','f','j' };
	char search1[] = {'0','a','e','j','z'};
	cout << endl;

	cout << "Char searching..." << endl;
	for (int i = 0; i < sizeof(search1) / sizeof(search1[0]); i++)
	{
		int index = BinarySearch(arr1, sizeof(arr1) / sizeof(arr1[0]),sizeof(char), & search1[i], &char_compare);
		cout << "The result is: " << index << endl;
	}
	system("pause");
	return 0;
}

穷举搜索

有20枚硬币,可能包括4种类型:1元、5角、1角和5分。

已知20枚硬币的总价值为10元,求各种硬币的数量。 例如:4、11、5、0就是一种方案。

而8、2、10、0是另一个可能的方案,显然方案并不是 唯一的,请编写程序求出类似这样的不同的方案一共有多少种?

(1)编程思路。 直接对四种类型的硬币的个数进行穷举。其中,1元最多10枚、5角最多20枚、1角最多 20枚、5分最多20枚。

如果以元为单位,则5角、1角、5分会化成浮点型数据,容易计算出错。可以将1 元、5角、1角、5分变成100分、50分、10分和5分,从而全部采用整型数据处理。

#include <iostream>
#include <string>

using namespace std;

int main()
{
	int a100 = 0; //one dollar coin
	int a50 = 0;
	int a10 = 0;
	int a5 = 0;
	int cnt = 0;

	for (a100 = 0; a100 <= 10; a100++)
	{
		for (a50 = 0; a50 <=(1000-a100*100)/50; a50++)
		{
			for (a10 = 0; a10 <= (1000-a100*100-a50*50)/10; a10++)
			{
				for (a5 = 0; a5 <= (1000 - a100 * 100 - a50 * 50 - a10*10) / 5; a5++)
				{
					if ((a100 * 100 + a50 * 50 + a10 * 10 + a5 * 5) == 1000 && (a100 + a50 + a10 + a5) == 20)
					{
						cout << a100 << "," << a50 << "," << a10 << "," << a5 << "," << endl;
						cnt++;
					}
				}
			}
		}

	}
	cout << "The total method to have the $10 dollar with 20 coin is: " << cnt << endl;


	system("pause");
	return 0;
}

穷举法(枚举法)的基本思想是:列举出所有可能的情况,逐个判断有哪些是符合问题所要求 的条件,从而得到问题的全部解答。 它利用计算机运算速度快、精确度高的特点,对要解决问题的所有可能情况,一个不漏地进行检 查,从中找出符合要求的答案。

用穷举算法解决问题,通常可以从两个方面进行分析:

(1)问题所涉及的情况:问题所涉及的情况有哪些,情况的种数必须可以确定。把它描述 出来。应用穷举时对问题所涉及的有限种情形必须一一列举,既不能重复,也不能遗漏。重复列 举直接引发增解,影响解的准确性;而列举的遗漏可能导致问题解的遗漏。

(2)答案需要满足的条件:分析出来的这些情况,需要满足什么条件,才成为问题的答案。 把这些条件描述出来。

并行搜索

并发的基本概念

所谓并发是在同一实体上的多个事件同时发生。并发编程是指在在同一台计算机上“同时” 处理多个任务。

在这里插入图片描述

要理解并发编程,我们必须要理解如下一些基本概念: 计算机就像一座工厂,时刻在运行,为人类服务。它的核心是CPU,它承担了所有的计算任 务,就像工厂的一个现场指挥官。

在这里插入图片描述

进程就像工厂里的车间,承担“工厂”里的各项具体的“生产任务”,通常每个进程对应一 个在运行中的执行程序,比如,QQ和微信运行的时候,他们分别是不同的进程。

因为特殊原因,现场指挥官人才短缺,整个工厂只有一个指挥官,一次只能指导一个车间生 产,而所有的车间都必须要有现场指挥官在场才能生产。也就是说,一个车间开工的时候, 其他车间都必须停工。

背后的含义:任一时刻,单个CPU一次只能运行一个进程,此时其他进程处于非运行状态。

在这里插入图片描述

一个车间(进程)可以包括多条生产线,线程就好比车间(进程)里的生产线。所有生产线 (设备和人)都属于同一车间的资源,受车间统一调度和调配,并共享车间所有资源(如空 间或洗手间)。

背后的含义:一个进程可以拥有多个线程,每个线程可以可以独立并行执行,多个线程共 享同一进程的资源,受进程管理。

在这里插入图片描述

理解了以上这些概念后,我们接下来再继续讲解并行搜索的概念: 假设我们要从很大的一个无序的数据集中进行搜索,

假设我们的机器可以一次性容纳这么多 数据。从理论上讲,对于无序数据,如果不考虑排序,已经很难从算法层面优化了。而利用 上面我们提到的并行处理思想,我们可以很轻松地将检索效率提升多倍。具体实现思路如下: 将数据分成N个块,每个块由一个线程来并行搜索。

#include <iostream>
#include <string>
#include <Windows.h>
#include <time.h>

using namespace std;

#define TEST_SIZE	(1024*1024*200)
#define NUMBER	20

typedef struct _search 
{
	int* data;
	size_t start;
	size_t end;
	size_t count;
}search;

//int main1()
//{
//	int* data = NULL;
//	int count = 0;
//
//	data = new int[TEST_SIZE];
//
//	for (int i = 0; i < TEST_SIZE; i++)
//	{
//		data[i] = i;
//	}
//
//	time_t start = 0, end = 0;
//	time(&start);
//
//	for (int j = 0; j < 10; j++)
//	{
//		for (int i = 0; i < TEST_SIZE; i++)
//		{
//			if (data[i] == NUMBER)
//			{
//				count++;
//			}
//		}
//	}
//
//	time(&end);
//	cout << "The time used for the search function is: " << end - start << endl;
//	system("pause");
//	return 0;
//}

DWORD WINAPI ThreadProc(void* lpParam)
{
	search* s = (search*)lpParam;
	time_t start, end;

	cout << "The new thread is executing..." << endl;
	time(&start);
	for (int j = 0; j < 10; j++)
	{
		for (size_t i = s->start; i < s->end; i++)
		{
			if (s->data[i] == NUMBER)
			{
				s->count++;
			}
		}
	}
	time(&end);
	cout << "The required time to searching the data is: " << end - start << endl;
	return 0;
}

int main()
{
	int* data = NULL;
	int count = 0;
	int mid = 0;
	search s1, s2;
	data = new int[TEST_SIZE];

	for (int i = 0; i < TEST_SIZE; i++)
	{
		data[i] = i;
	}

	mid = TEST_SIZE / 2;
	s1.data = data;
	s1.start = 0;
	s1.end = mid;
	s1.count = 0;

	s2.data = data;
	s2.start = mid + 1;
	s2.end = TEST_SIZE -1;
	s2.count = 0;

	DWORD threadID1; //Thread 1 identity
	HANDLE hThread1; //Thread 1 handle

	DWORD threadID2; //Thread 2 identity
	HANDLE hThread2; //Thread 2 handle

	cout << "Creating the threads..." << endl;

	hThread1 = CreateThread(NULL, 0, ThreadProc, &s1, 0, &threadID1); //Creating first thread
	hThread2 = CreateThread(NULL, 0, ThreadProc, &s2, 0, &threadID2); // Creating second thread

	WaitForSingleObject(hThread1, INFINITE);
	WaitForSingleObject(hThread2, INFINITE);
	cout << "The process is waiting the thread to return..." << endl;
	cout << "The total count for the search value is: " << s1.count + s2.count << endl;
	system("pause");
	return 0;
}
  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值