前言
上次总结了其他的三种算法:选择排序、冒泡排序和插入排序,这次总结一个更加高效的排序算法——快速排序法,如果想要了解其余三种算法,请移步c#版选择法、冒泡法、插入法和快速排序法分析与对比
快速排序法
步骤:
- 1.随便找一个基准数,一般都拿左边第一个数当做基准数
- 2.给基准数找到一个合适的位置,让其左边的数都小于它,右边的数都大于它
- 3.这个基准数的位置自然将队列分为了两部分,再对这两部分分别进行步骤一和步骤二,直到排序完成
- 首先我们以第一个数为基准,也就是5
- 定义两个变量i和j,j从右往左找一个比5小的数,找到4停止;i从左向右找一个比5大的数,也就是7停止;
- 将4和7交换位置
- 两个变量继续寻找,这里需要强调一点,一定是让j先从右边开始找,这个之后再做解释
- 这是j找到了1,而i与j相遇了,代表探测结束,这时让基准数与1进行位置交换,通过第一次的探测,我们已经找到了基准数在队列中的位置,这时的队列为1,4,0,3,5,7,9,6,,可以发现,5对左边都是比他小的数,而右边都是比他大的数
- 队列以“5”为分界点,分成了两部分,我们在分别对这两部分应用之前的步骤,知道队列排序完成
为什么一定要J先找?
我们看下边这种情况,如果i先找,那么i和j将会在“7”相遇,这时将二者交换,那么5的左边就不是都比他小的数了
之后左边再次执行之前的步骤:(右边同理)
画下划线的数字是基准数,红色的是分界点
注意:
队列不断的被归为的基准数分为两部分的时候,左右两部分通过递归调用来完成排序,也就是说不断的调用自己来完成排序
代码
<strong style="font-size:24px;"> </strong><span style="font-size:14px;">/// <summary>
/// 快速排序法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button4_Click(object sender, EventArgs e)
{
//哈希表转整数数组
int[] s = hs.ToArray();
DateTime time1 = DateTime.Now;
int low=0; //记录目标数组的起始位置
int high=s.Length-1; //记录目标数组的结束位置
QuickSortFunction(s, low, high);
DateTime time2 = DateTime.Now;
textBox4.Text = DateDiff(time1, time2);
for (int i = listBox1.Items.Count - 1; i >= 0; i--)
{
listBox1.Items.RemoveAt(i);
}
for (int i = 0; i < s.Length; i++)
{
this.listBox1.Items.Add(s[i]);
}
}
/// <summary>
/// 快速排序过程
/// </summary>
/// <param name="array">数组</param>
/// <param name="low">低位目标数组下标</param>
/// <param name="high">高位目标数组下边</param>
private static void QuickSortFunction(int[] array, int low, int high)
{
int keyValuePosition; //记录关键值的下标
//当传递的目标数组含有两个以上的元素时,进行递归调用。(即:当传递的目标数组只含有一个元素时,此趟排序结束)
if (low < high)
{
keyValuePosition = keyValuePositionFunction(array, low, high); //获取关键值的下标(快排的核心)
QuickSortFunction(array, low, keyValuePosition - 1); //递归调用,快排划分出来的左区间
QuickSortFunction(array, keyValuePosition + 1, high); //递归调用,快排划分出来的右区间
}
}
/// <summary>
/// 找出关键值位置
/// </summary>
/// <param name="array">数组</param>
/// <param name="low">低位下标</param>
/// <param name="high">高位下标</param>
/// <returns>关键值下标</returns>
private static int keyValuePositionFunction(int[] array, int low, int high)
{
int i = low; //记录目标数组的起始位置(后续动态的左侧下标)
int j = high; //记录目标数组的结束位置(后续动态的右侧下标)
int keyValue = array[low]; //数组的第一个元素作为关键值
int temp;
//当 (左侧动态下标 == 右侧动态下标) 时跳出循环
while (i< j)
{
while (i < j && array[j] > keyValue) //必须先从右边开始,逐渐向左移动,直至找到<=keyValue的下标
{
j--;
}
while (i < j && array[j] <= keyValue) //从左边开始,直至找到>=keyValue的下标
{
i++;
}
if(i < j) //如果leftIndex < rightIndex,则交换左右动态下标所指定的值;当leftIndex==rightIndex时,跳出整个循环
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
//当左右两个动态下标相等时(即:左右下标指向同一个位置),此时便可以确定keyValue的准确位置
temp = keyValue;
if (temp < array[j]) //当keyValue < 左右下标同时指向的值,将keyValue与rightIndex - 1指向的值交换,并返回rightIndex - 1
{
array[low] = array[j - 1];
array[j - 1] = temp;
return j - 1;
}
else //当keyValue >= 左右下标同时指向的值,将keyValue与rightIndex指向的值交换,并返回rightIndex
{
array[low] = array[j];
array[j] = temp;
return j;
}
}
</span>
总结:
之所以快速排序法比较高效是因为他交换的位置不是相邻的交换,而是跨度更宽的位置的交换,这样可以更加精准的确定数的位置,算法很有意思,希望可以学习更多的内容