数据结构与算法之四 搜索算法

目标

在本章中,你将学习: 使用线性搜索技术搜索数据和二叉搜索技术搜索数据 

线性搜索:
是最简单的搜索方法, 也称作顺序搜索, 包括将用该条目逐一与列表中的条目进行比较, 线性搜索通过比较所需的元素与列表中第一个元素进行。

如果值不匹配:
       则所需的元素将与列表中的第二个元素作比较。
如果值还是不匹配:
     则所需的元素将与列表中的第三个元素作比较。
这个过程将一直持续下去,直到:
    找到所需的元素或到达列表的未尾为止。
使用线性搜索算法编写一个算法以搜索 员工记录列表 中给定的员工的工号:
1.  读取要搜索的工号     ( 首先确定你要找的工号 )
2. 设置 i = 0   n 是数组的最大值下标 ( 上界 )
3. 重复步骤 4 直到 i > n arr[i] = employee ID
4. i 值增加 1
5. 如果 i > n:
           显示 未找到
     否则
           显示 已找到

搜索算法的效率是由算法的运行时间决定的。
在最佳情况下:
元素位于列表的第一个位置。
比较次数为 1
线性搜索的最佳的效率是 O(1)
在最差情况下:
元素 位于列表中最后一个位置或者它根本不存在于该列表中
比较次数为元素的数。
线性搜索最差的效率是 O(n)

在平均情况下:
线性搜索的平均比较数由最佳和最差搜索中的平均比较数决定
线性搜索的平均效率是 1/2(n + 1)


课间思考

您要在一个包含 5000 个元素的数组中应用线性搜索来搜索一个元素,如果在搜索的 最后,您发现该元素不在该数组中,则为了在该给定的列表中搜索所需的元素您要 进行多少次的比较?


答案:
5,000


问题描述:
编写一个在含有最多 20 个数的数组中使用线性搜索算法搜索一个给定数的程序, 如果要搜索的元素在列表中出现多次,则该程序应该显示第一次出现的位置,还 应该显示所作的比较总数。


二叉搜索算法:
用于搜索大列表, 以十分少的比较来搜索数据, 只要要搜索的列表已经排序,则可以使用二叉搜索算法
考虑一个示例。
您要在以字母顺序排列的电话目录中搜索名字 Steve
要使用二叉搜索算法搜索名字 Steve
在中间打开电话目录以确定哪一半包含该名字。
在那一半的中间再打开以确定哪一半包含该名字。
重复此过程直到找到所需的名字为止。
二叉搜索每次就减少了一半的搜索页数。


编写一个算法以实现二叉搜索算法。
1. 接受要搜索的元素 ( 确定要查找的值 )
2. 设置 lowerbound = 0 
3. 设置 upperbound = n – 1
4. 设置 mid = (lowerbound + upperbound)/2
5. 如果 arr[mid] = 所需元素:
a. 显示 已找到
b. 转到步骤 10
6. 如果所需元素 < arr[mid]:
a. 设置 upperbound = mid – 1


7. 如果所需元素 > arr[mid]:
a. 设置 lowerbound = mid + 1
8. 如果 lowerbound <= upperbound:
a. 转至步骤 4
9. 显示 未找到
10. 退出


在二叉搜索算法中的每个步骤中,搜索区域都减半。
该算法的最好情况是如果要搜索的元素正好位于列表的最中间的位置:
此情况的比较数为 1
在最差情况下,列表中未找到所需元素
在第一次对分后,搜索空间减少到 n/2 个元素,其中 n 是原始列表中的元素数。
第二次对分后,搜索空间减少到 n/4 ,即 n/22 个元素。
经过第 i 次对分后,搜索空间减少到 n/2i  元素。


课间思考


___________ 搜索算法中,您从列表的一端开始并且扫描整个列表直到找到所需 项或到达列表的末尾为止。


答案:
线性
要执行 __________ 搜索算法,列表应该是经排序的。
答案:
二叉

问题描述:
编写一个程序,它使用二叉搜索在含有最多 20 个元素的数组中搜索一个数,假设 数组元素是以升序输入的。如果数组中有多个要搜索的数,则发现一个匹配后搜 索就停止了。程序还应该显示所作的比较总数。


小结
在本章中,你已经学到:
线性搜索的最佳效率是 O(1) ,最差效率 O(n)
要应用二叉搜索算法,应该确保要搜索的列表是排过序的。
二叉搜索的最佳效率是 O(1) ,最差效率是 O(log n)

/*从8个数中查找数字*/
using System;

class Ban
{
	public static void Main(string[]args)
	{
		//int []arr={8001,8002,8003,8004,8007,8010,8005,8009}; //定义有8个整数的数组		
		Console.WriteLine("请输入您的工号个数:");
		int n; //n为数组的上界
		n=Convert.ToInt32(Console.ReadLine());	//n就是数组的长度(个数)
		
		int []arr=new int[n];		//定义有10个数字的数组
		for(int j=0;j<n;j++)
		{
			Console.Write("请输入第"+(j+1).ToString()+"个数:");
			arr[j]=Convert.ToInt32(Console.ReadLine());
		}		
		
		//3.重复步骤 4 直到 i > n 或 arr[i] = id 才退出.
	 char ch='y'; //定义我们不断查找的条件,如果为y|Y,则一直查找;n|N:则退出查找.
	 
	 while((ch=='y')||(ch=='Y'))
	 {
	 	Console.WriteLine("请输入您要查找的数字:");
	 	int id=Convert.ToInt32(Console.ReadLine());	//定义要查找的数据元素	
		
		int lowerbound=0;
		int upperbound=n-1;
		int mid=(lowerbound+upperbound)/2;	//中间值下标
		
		//13	 
		while(lowerbound<=upperbound)	//实现找合适的中间值索引
		{
			if(id<arr[mid])
				upperbound=mid-1;
			else
				lowerbound=mid+1;
				
			mid=(lowerbound+upperbound)/2;	
			Console.WriteLine("low:"+lowerbound+"mid:"+mid+"upper:"+	upperbound);	
		}
		//针对找到数据元素,代码
				Console.WriteLine(arr[mid]);
		if(id==arr[mid])
				Console.WriteLine("ok");
		else		
			Console.WriteLine("没有找到....");
			
		Console.WriteLine("您是否继续查找,是(y|Y),否(n|N):");
	  ch=Convert.ToChar(Console.ReadLine());	
	}//不断查找结束		
	}
}


/*使用二叉搜索在含有最多20个元素的数组中搜索一个数,假设数组是以升序输入的。如果数组中有多个要搜索的数,则发现一个匹配后搜索就停止了。
程序还应该显示所作的比较总数。
*/
using System;

class BinarySearch
{
	static void Main(string[]args)
	{
		int[]arr=new int[20];	//要搜索的数组
		int n;	//数组中的元素数
		int i;	//获取在数组中存储的元素数
		
		while(true)
		{
			Console.Write("请输入数组的元素个数:");
			string s=Console.ReadLine();
			n=Int32.Parse(s);
			if((n>0)&&(n<=20))
				break;
			else
				Console.WriteLine("\n数组最少1个元素,最多20个元素.\n");	
		}
		//接受数组元素
		Console.WriteLine("------------------------------------------");
		Console.WriteLine("---------------输入数组元素---------------");
		Console.WriteLine("------------------------------------------");
		
		for(i=0;i<n;i++)
		{
				Console.Write("<"+(i+1)+">");
				string s1=Console.ReadLine();
				arr[i]=Int32.Parse(s1);
		}
		char ch='y';
		do
		{
			//要搜索的数
			Console.Write("请键入您要查找的数");			
			int item=Convert.ToInt32(Console.ReadLine());
			//应用二叉搜索
			int lowerbound=0;
			int upperbound=n-1;
			
			//获取中间元素的索引
			int mid=(lowerbound+upperbound)/2;
			int ctr=1;
			
			while((item!=arr[mid])&&(lowerbound<=upperbound))	//在数组中搜索元素的循环
			{
				if(item>arr[mid])
					lowerbound=mid+1;
				else
					upperbound=mid-1;
				mid=(lowerbound+upperbound)/2;
				//ctr++;
			}
	
			if(item==arr[mid])
				Console.Write("\n"+item.ToString()+"发现了位置:"+(mid+1).ToString());
			else
				Console.Write("\n"+item.ToString()+"在数组中没有发现");
				Console.Write("\n比较次数:"+ctr);
				Console.Write("\n继续搜索(y/n)");
				ch=char.Parse(Console.ReadLine());
		}while((ch=='y')||(ch=='Y'));
}	
}

/*
编写一个在含有20个数的数中使用线性搜索算法一个给定数的程序,如果要搜索的元素在列表中出现多次,则该程序应该显示第一次出现的位置,还应该显示所作
的比较总数。
*/
using System;

class SequentialSearch
{
	static void Main(string[]args)
	{
		int[]arr=new int[20];	//要搜索的数组
		int n;								//数组中的元素
		int i;	//获取在数组中存储的元素
		
		while(true)
		{
			Console.Write("请输入数组的元素个数:");
			string s=Console.ReadLine();
			n=Int32.Parse(s);
			if((n>0)&&(n<=20))
				break;
			else
				Console.WriteLine("\n数组最少1个元素,最多20个元素.\n");	
		}
		//接受数组元素
		Console.WriteLine("------------------------------------------");
		Console.WriteLine("---------------输入数组元素---------------");
		Console.WriteLine("------------------------------------------");
		
		for(i=0;i<n;i++)
		{
				Console.Write("<"+(i+1)+">");
				string s1=Console.ReadLine();
				arr[i]=Int32.Parse(s1);
		}
		char ch='y';
		int  ctr;
		
		do
		{
			//接受要搜索的数
			Console.Write("\n请输入您要搜索的数:");
			int item=Convert.ToInt32(Console.ReadLine());
			//应用线性搜索
			ctr=0;
			for(i=0;i<n;i++)
			{
				ctr++;
				if(arr[i]==item)
				{
					Console.WriteLine("\n"+item.ToString()+"发现在位置"+(i+1).ToString());
					break;	
				}	
			}
			if(i==n)
			{
				Console.WriteLine("\n"+item.ToString()+"在数组中没有发现元素");
				Console.WriteLine("\n比较的次数为:"+ctr);
				Console.Write("\n继续搜索(y/n):");
				ch=Char.Parse(Console.ReadLine());	
			}
		}while((ch=='Y')||(ch=='y'));
	}	
}


你可能感兴趣的:(算法,数据,搜索,归并排序,排序算法)