关于快速排序算法(一个90%的人都不懂其原理、99.9%的人都不能正常写出来的算法.)
一、奇怪的现象
研究快速排序很久了,发现一个古怪的实情:这算法描述起来很简单,写一个正确的出来实在不容易.写一个优秀的快速排序算法更是难上加难.
也难怪该算法提出来过了很久才有人写出一个正确的算法,过了很久才优秀的版本出来.
二、原理描述
- 从数列中挑出一个元素,称为 "基准"(pivot),
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序.
三、最容易让人理解的版本
一个List形式的数组,找到其中的第一个做基准,遍历剩下的数据,然后创建两个左右List,大的放右边,小的放左边.然后对左右List各自进行如上操作.......
详情见代码
using System;
using System.Collections.Generic;
using System.Text;
namespace test
{
class Program
{
static void Main(string[]args)
{
List<int> array=new List<int>();
array.AddRange(new int[]{3,2,9,5,8,6,23,23,222,12,21});
var t1=DateTime.Now.Ticks;
sort(array);
var t2=DateTime.Now.Ticks;
Console.WriteLine(t2-t1);
Console.ReadLine();
}
static int Count=0;
public static void sort(List<int> array)
{
var guid=Count++;
Console.WriteLine();
Console.Write("目标字符串:("+guid+")");
Show(array);
if (array.Count<=1) {
return;
}
if (array.Count==2) {
if (array[0]>array[1]) {
var temp=array[0];
array[0]=array[1];
array[1]=temp;
Console.Write("双值交换:");
Show(array);
}
}
else{
var xData=array[0];
var leftList=new List<int>();
var rightList=new List<int>();
for (int i = 1; i < array.Count; i++) {
var t=array[i];
if (t<=xData) {
leftList.Add(t);
}else{
rightList.Add(t);
}
}
Console.WriteLine("中间值:"+xData);
Console.Write("左边的字符串("+guid+"):");
Show(leftList);
Console.Write("右边的字符串("+guid+"):");
Show(rightList);
sort(leftList);
Console.Write("左边的字符串(排序后)("+guid+"):");
Show(leftList);
sort(rightList);
Console.Write("右边的字符串(排序后)("+guid+"):");
Show(rightList);
array.Clear();
array.AddRange(leftList);
array.Add(xData);
array.AddRange(rightList);
Console.Write("排好的("+guid+"):");
Show(array);
Console.WriteLine();
leftList.Clear();
rightList.Clear();
}
}
public static void Show(List<int>array){
foreach (var a in array) {
Console.Write(a+",");
}
Console.WriteLine();
}
}
}
四、正确但不优化的版本
using System; namespace Sort { class Program { static void Main(string[] args) { string result = string.Empty; int[] unsort = { 2, 0, 3, 7, 5,6 }; //快速排序 QuickSort(unsort, 0, unsort.Length - 1); Console.ReadLine(); } /// <summary> /// 调用快速排序算法 /// </summary> /// <param name="unsort">待排序的整形数组</param> /// <param name="left">左边起始点</param> /// <param name="right">右边结束点</param> public static void QuickSort(int[] unsort, int left, int right) { if (left < right) { //获取一次排序的中间索引位置 int midPosition = GetSplitNum(unsort, left, right); //递归实现 QuickSort(unsort, left, midPosition - 1); QuickSort(unsort, midPosition + 1, right); } } static int ORDER_INDEX=1; /// <summary> /// 获取一次排序的中间索引位置 /// </summary> /// <param name="unsort">待排序的整形数组</param> /// <param name="left">左边起始点</param> /// <param name="right">右边结束点</param> public static int GetSplitNum(int[] unsort, int left, int right) { int splitNum = unsort[left]; while (left < right) { /** * 从右端开始比较 * (1)假如从右端过来的数比分隔数要大,则不用处理 * (2)假如从右端过来的数比分隔数要小,则需要挪到分隔线左边 * */ while (left < right && splitNum <= unsort[right]) { right--; } unsort[left] = unsort[right]; GetPrint(unsort); /** * 从从端开始比较 * (1)假如从左端过来的数比分隔数要小,则不用处理 * (2)假如从左端过来的数比分隔数要大,则需要挪到分隔线右边 * */ while (left < right && splitNum >= unsort[left]) { left++; } unsort[right] = unsort[left]; GetPrint(unsort); } //一趟比较之后,分隔数的位置就可以确认起来 unsort[left] = splitNum; Console.WriteLine(string.Format("第{0}轮排序完毕",(ORDER_INDEX++))); GetPrint(unsort); return left; } /// <summary> /// 打印输出结果 /// </summary> /// <param name="unsort">数据</param> public static string GetPrint(int[] unsort) { string result = string.Empty; foreach (int n in unsort) { if (!string.IsNullOrEmpty(result)) { result += string.Format("->{0}", n); } else { result = string.Format("{0}", n); } } Console.WriteLine(result); return result; } public static string GetPrint(int[] unsort,int replaceIndex) { string result = string.Empty; foreach (int n in unsort) { if (!string.IsNullOrEmpty(result)) { result += string.Format("->{0}", n); } else { result = string.Format("{0}", n); } } Console.WriteLine(result+" ==>"+replaceIndex); return result; } } }
少侠,我看你气度不凡天赋异禀,骨骼精奇,这么帅,来了就帮推荐一把吧
我的最近更新

浙公网安备 33010602011771号