第4章 基础查找算法
有两种对列表内数据进行查找的方法:顺序查找和二叉查找。当数据项在列表内随机排列的时候可以使用顺序查找,而当数据项在列表内有序排列的时候则会用到二叉查找。
4.1顺序查找
class Chapter4
{
static void Main()
{
int[] numbers = new int[100];
StreamReader numFile = File.OpenText(@"c:/numbers.txt");
for (int i = 0; i < numbers.Length; i++)
numbers[i] = Convert.ToInt32(numFile.ReadLine(), 10);
int searchNumber;
Console.Write("Enter a number to search for:");
searchNumber = Convert.ToInt32(Console.ReadLine(), 10);
bool found;
found = SeqSearch(numbers, searchNumber);
if (found)
Console.WriteLine(searchNumber + "is in the array.");
else
Console.WriteLine(searchNumber + "is not in the array.");
}
static bool SeqSearch(int[] arr, int sValue)
{
for (int index = 0; index < arr.Length; index++)
if (arr[index] == sValue)
return true;
return false;
}
}
4.1.1查找最小值和最大值
查找最小值
static int FindMin(int[] arr)
{
int min = arr[0];
for (int i = 1; i < arr.Length; i++)
if (arr[i] < min)
min = arr[i];
return min;
}
4.1.2自组织数据加快顺序查找速度
因为要查找的数据大概会遵循“80-20”规则,所以允许数据进行组织是明智的。其中,“80-20”规则意味着在数据集合上80%的查找操作都是为了查找集合内20%的数据。自组织将最终把20%的数据放在数据集合的开始部分,这样顺序查找就可以快速地找到它们了。
可以很容易的修改SeqSearch方法来包含自组织。下面是此方法的一个基本的修正:
static int SeqSearch(int[] arr, int sValue)
{
for (int index = 0; index < arr.Length; index++)
if (arr[index] == sValue)
{
swap(index, 0);
return index;
}
return false;
}
static void swap(int[] arr,int item1, int item2)
{
int temp = arr[item1];
arr[item1] = arr[item2];
arr[item2] = temp;
}
正如上述已经修改的一样,用seqSearch方法的问题就是在多次查找过程中会相当多次地把频繁访问到的数据项移来移去。而这里希望把移动到数据集合开始处的数据项保留下来,并且当对集合后部一个后续数据项成功定位的时候也不用把以保留的数据项移动回去。
两种方法可以实现这个目标,第一种是只交换那些找到的且位置远离数据集合开始处的数据项,再次遵循80-20规则,就是只有当数据项的位置位于数据集合前20%数据项之外的时候才可以把它重新定位到数据集合的开始部分。下面是按照第一种方法改写的代码:
static int SeqSearch(int[] arr, int sValue)
{
for (int index = 0; index < arr.Length; index++)
if (arr[index] == sValue && index > (arr.Length * 0.2))
{
swap(index, 0);
return index;
}
else
if (arr[index] == sValue)
return index;
return -1;
}
另外一种方法是重写SeqSearch方法。从而使得此方法可以把找到的数据项与数据集合内此项之前的元素进行交换。类似于数据排序时所用的冒泡排序算法
static int SeqSearch(int[] arr, int sValue)
{
for (int index = 0; index < arr.Length; index++)
if (arr[index] == sValue)
{
swap(arr,index, index-1);
return index;
}
return -1;
}
4.2二叉查找算法
这里使用c#语言编写的函数(迭代方式)
public int binSearch(int value)
{
int upperBound, lowerBound, mid;
upperBound = arr.Length - 1;
lowerBound = 0;
while (lowerBound <= upperBound)
{
mid = (upperBound + lowerBound) / 2;
if (arr[mid] == value)
return mid;
else
if (value < arr[mid])
upperBound = mid - 1;
else
lowerBound = mid + 1;
}
return -1;
}
下面是一个采用二叉查找方法来查找数组的程序
static void Main(string[] args)
{
Random random = new Random();
CArray mynums = new CArray(10);
for (int i = 0; i <= 9; i++)
mynums.Insert(random.Next(100));
mynums.BubbleSort();
mynums.DisplayElements();
int position = mynums.binSearch(77);
if (position >-1)
{
Console.WriteLine("found item");
mynums.DisplayElements();
}
else
Console.WriteLine("Not in the array");
Console.Read();
}
4.3递归二叉查找算法
尽管在上节中讲述的二叉查找算法是正确的,但它其实不是解决问题的通常方案。二叉查找算法是一种递归算法,因为此算法会不断的划分数组直到找到所要的数据项才会终止,而每次划分都是表示成一个比原有问题规模更小的同类问题。
public int RbinSearch(int value,int lower,int upper)
{
if (lower > upper)
return -1;
else
{
int mid;
mid = (int)(upper + lower) / 2;
if (value < arr[mid])
return RbinSearch(value, lower, mid - 1);
else if (value == arr[mid])
return mid;
else
return RbinSearch(value, mid - 1, upper);
}
}
内置的二叉查找方法
public int Bsearch(int value)
{
return Array.BinarySearch(arr, value);
}
当内置的二叉查找方法与用户定制的方法进行比较的时候,内置方法始终比用户定制方法执行速度快10倍。