using System;
namespace ConsoleApp_Arithmetic_LookupAndSorting
{
/// <summary>
/// 找到第K大的数
/// </summary>
public class FindK
{
/// <summary>
/// 调用的方法
/// </summary>
public static void CallingMethod()
{
FindK p = new FindK();
int[] v = new int[] { 100, 200, 50, 23, 300, 560, 789, 456, 123, 258 };
p.FindKLargest(v, 0, v.Length, 3);
Console.WriteLine(v[v.Length - 3]);
Console.Read();
}
/// <summary>
/// 找到第K大的数
/// </summary>
/// <param name="v">查找的列表</param>
/// <param name="first">起始位置</param>
/// <param name="last">结束位置</param>
/// <param name="k">要查找的数是第K大</param>
void FindKLargest(int[] v, int first, int last, int k)
{
//表示分表中值的索引
int index = 0;
index = PivotIndex(v, first, last);
if (index == k)
{
//找到了K大
return;
}
if (index > k)
{
//只在左子表中查找
FindKLargest(v, first, index, k);
}
else
{
//只在右子表中查找
FindKLargest(v, index, last, k);
}
}
/// <summary>
/// 交换位置
/// </summary>
/// <param name="v"></param>
/// <param name="index1"></param>
/// <param name="index2"></param>
private void Swrap(int[] v, int index1, int index2)
{
int temp = v[index1];
v[index1] = v[index2];
v[index2] = temp;
}
/// <summary>
/// 将向量V中索引{first,last)划分成两个左子表和右子表
/// </summary>
/// <param name="v">向量V</param>
/// <param name="first">开始位置</param>
/// <param name="last">结束位置</param>
private int PivotIndex(int[] v, int first, int last)
{
if (last == first)
{
return last;
}
if (last - first == 1)
{
return first;
}
int mid = (first + last) / 2;
int midVal = v[mid];
//交换v[first]和v[mid]
Swrap(v, first, mid);
int scanA = first + 1;
int scanB = last - 1;
for (; ; )
{
while (scanA <= scanB && v[scanA] < midVal)
{
scanA++;
}
while (scanB > first && midVal <= v[scanB])
{
scanB--;
}
if (scanA >= scanB)
{
break;
}
Swrap(v, scanA, scanB);
scanA++;
scanB--;
}
Swrap(v, first, scanB);
return scanB;
}
}
}
using System;
using System.Collections.Generic;
namespace ConsoleApp_Arithmetic_LookupAndSorting
{
/// <summary>
/// 归并排序
/// </summary>
class MergeSort
{
/// <summary>
/// 调用的方法
/// </summary>
static void CallingMethod()
{
int[] array = new int[] { 2, 5, 56, 1, 78, 6, 55, 3, 8, 9, 123, 258, 4568 };
MergeSort p = new MergeSort();
p.MergerSort(array, 0, array.Length);
foreach (int i in array)
{
Console.Write(i.ToString() + " ");
}
Console.Read();
}
public void MergerSort(int[] v, int first, int last)
{
if (first + 1 < last)
{
int mid = (first + last) / 2;
MergerSort(v, first, mid);
MergerSort(v, mid, last);
Merger(v, first, mid, last);
}
}
public void Merger(int[] v, int first, int mid, int last)
{
Queue<int> tempV = new Queue<int>();
int indexA, indexB;
//设置indexA,并扫描subArray1 [first,mid]
//设置indexB,并扫描subArray2 [mid,last]
indexA = first;
indexB = mid;
//在没有比较完两个子标的情况下,比较 v[indexA]和v[indexB]
//将其中小的放到临时变量tempV中
while (indexA < mid && indexB < last)
{
if (v[indexA] < v[indexB])
{
tempV.Enqueue(v[indexA]);
indexA++;
}
else
{
tempV.Enqueue(v[indexB]);
indexB++;
}
}
//复制没有比较完子表中的元素
while (indexA < mid)
{
tempV.Enqueue(v[indexA]);
indexA++;
}
while (indexB < last)
{
tempV.Enqueue(v[indexB]);
indexB++;
}
int index = 0;
while (tempV.Count > 0)
{
v[first + index] = tempV.Dequeue();
index++;
}
}
}
}
using System;
namespace ConsoleApp_Arithmetic_LookupAndSorting
{
/// <summary>
/// 快速排序
/// </summary>
class QuickSort
{
/// <summary>
/// 调用的方法
/// </summary>
static void CallingMethod()
{
QuickSort p = new QuickSort();
int[] v = new int[] { 800, 150, 300, 45, 650, 550, 500, 400, 2, 350, 450, 900, 1 };
p.Sort(v, 0, v.Length);
foreach (int i in v)
{
Console.Write(i.ToString() + " ");
}
Console.Read();
}
public void Sort(int[] v, int first, int last)
{
if (last - first <= 1)
{
return;
}
if (last - first == 2)
{
//有两个元素的子表
if (v[first] > v[last - 1])
{
Swrap(v, first, last - 1);
}
return;
}
else
{
int pivotIndex = PivotIndex(v, first, last);
Sort(v, first, pivotIndex);
Sort(v, pivotIndex + 1, last);
}
}
/// <summary>
/// 交换位置
/// </summary>
/// <param name="v"></param>
/// <param name="index1"></param>
/// <param name="index2"></param>
private void Swrap(int[] v, int index1, int index2)
{
int temp = v[index1];
v[index1] = v[index2];
v[index2] = temp;
}
/// <summary>
/// 将向量V中索引{first,last)划分成两个左子表和右子表
/// </summary>
/// <param name="v">向量V</param>
/// <param name="first">开始位置</param>
/// <param name="last">结束位置</param>
private int PivotIndex(int[] v, int first, int last)
{
if (last == first)
{
return last;
}
if (last - first == 1)
{
return first;
}
int mid = (first + last) / 2;
int midVal = v[mid];
//交换v[first]和v[mid]
Swrap(v, first, mid);
int scanA = first + 1;
int scanB = last - 1;
for (; ; )
{
while (scanA <= scanB && v[scanA] < midVal)
{
scanA++;
}
while (scanB > first && midVal <= v[scanB])
{
scanB--;
}
if (scanA >= scanB)
{
break;
}
Swrap(v, scanA, scanB);
scanA++;
scanB--;
}
Swrap(v, first, scanB);
return scanB;
}
}
}
using System;
namespace ConsoleApp_Arithmetic_LookupAndSorting
{
/// <summary>
/// 优化查找的方法,以提高查找的性能
/// </summary>
class Lookup_Optimize
{
#region 相关变量声明
/// <summary>
/// 声明一个数组,大小是1000
/// </summary>
static int[] Arr = new int[1000];//调用前,请先给数组赋值
#endregion
#region
/* 相关说明:
使顺序查找更快速:
自组织数据最快速的成功的顺序查找发生在被查找的数据元素位于数据集的开始部分。
通过将被找到的元素移动到数据集的起始部分你可以保证成功定位的数据项都位于数据集的前部。
这个策略背后的理念是我们可以将频繁搜索的项放置于数据集的前部来最优化搜索时间。
最后,所有最常被查找的数据项都被放置于数据集的起始部分。这是自组织的一个例子,
这种方式下,数据集不是由程序员在程序运行前组织,而是程序运行过程中由程序组织。
当待查找的数据大致遵循"80-20"原则,即对数据集80%的查找都是针对20%的数据时,你可以使用这种方式组织你的数据。
自动数据组织最终将这20%的数据放置在数据集的前部,这时顺序搜索将可以很快的找到它们。
这样的概率分布被称作帕累托分布,命名自维尔弗雷多·帕累托,其于十九世纪晚期在研究收入与财富分布的过程中发现了这些分布关系。
参见高德纳(1998, pp. 399 - 401)著作中更多关于数据集中这种概率分布的知识。
我们可以很容易的修改我们的SeqSearch方法来包含自动组织。以下是方法的第一部分:
*/
/*
一个频繁被访问的项目在许多次查找过程中可能被多次移动。我们要实现的目标是,
将移动到数据集第一位的那个项目保持在那里并且在数据集中随后的被成功定位的项出现时不将这个位于第一位的项向后移。
有两种方法可以实现这个目标。第一,我们可以只交换那些距数据集首部很远的找到的项。
我们只需要决定这个距数据集首部足够远而可以交换元素的标准。让我们再次使用"80-20"规则,
我们约定只有当查找到的数据项不在数据集的前20%的项中时我们才调整它的位置到数组的前部。
*/
/// <summary>
/// 使用这种类似起泡排序中数据排序方式的方法,最终最频繁被访问的项目将到达数据集的前部。
/// (arr[]数组内部顺序在每次查找后都会得到优化)
/// </summary>
/// <param name="sValue"></param>
/// <returns></returns>
static int SeqSearch(int sValue)
{
for (int index = 0; index < Arr.Length - 1; index++)
{
if (Arr[index] == sValue && index > (Arr.Length * 0.2))
{
swap(index, index - 1);
return index - 1;
}
else if (Arr[index] == sValue) //短路式的,因为如果没有在数据集中找到项,则没有理由测试索引是否在数据集中
return index;
}
return -1;
}
//如果查找成功,将找到的元素与数组的第一个元素交换,这个操作使用如下所示的swap函数:
static void swap(int item1, int item2)
{
int temp = Arr[item1];
Arr[item1] = Arr[item2];
Arr[item2] = temp;
}
#endregion
//正在查找的记录是有序的时,二叉查找算法(折半查找)[注意:不是二叉树查找]
/* 二叉查找算法:
要使用这个算法,我们首先要使我们的数据有序存储(升序最佳)与数组中(类似的数据结构同样工作)。
算法的第一步是确定要查找的最小与最大边界。在查找开始时这个范围就是数组的边界。
然后,我们计算数组的中间位置,把最小与最大边界索引值相加并除2。
存储于这个位置的元素将与待查找的值比较。如果它们相同,则目标值找到算法停止。
如果待查找的值比中间位置的值小,一个新的上界被计算出来 – 即现在的中间位置减1。
或者,待查找的值比中间位置的值大,将中间位置加1将作为新范围的下界。算法将迭代直到下界与上界相等,这表示数据被完整查找过。
如果这种情况发生,返回-1,表示数组中没有与待查找的值相等的元素。
*/
/// <summary>
/// 迭代的方式(效率比递归的高)
/// </summary>
static 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;
}
/// <summary>
/// 递归的方式(效率比较低)
/// (当一个有1000元素的数组使用这两种算法排序时,递归的算法一般要比迭代的算法慢10倍)
/// </summary>
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);
}
}
/// <summary>
/// 系统内置的查找方法(效率比较高)
/// </summary>
public int Bsearh(int value)
{
return Array.BinarySearch(Arr, value);
}
}
}