快速排序的核心思路和挖坑填坑和分治法。
首先取一个枢纽值,枢纽值一般选取分段两边和中间数字三者的中间项。
这时就先挖坑,把枢纽值所在项和第一项交换,成为第一项。然后再第一项挖坑,并且保存第一项所在的枢纽值。
=========================================
然后该项和最后项往前进行逐个判断,出现小于枢纽值的项就和坑交换位置。
交换过一次后,再从第一个项往前找大于枢纽值的项和坑交换位置。
=========================================
不断的交换的结果是枢纽值被移动到了中间项
之后再对枢纽值两边进行递归分治,直到排序完成
using System;
namespace DigPro
{
class Program
{
static void Main(string[] args)
{
Dig dig = new Dig();
dig.DigSort(dig.im, 0, dig.im.Length - 1);
dig.Cout();
}
}
class Dig
{
public int[] im = { 70, 8, 6, 99, 4, 56, 45, 3, 56, 78, 1 };
//lastDig表示上一次坑的位置,也就是枢纽值最后所在的位置。
//第一次为0,如果不想取第一个数就把想取得枢纽值和第一个交换,digLength表示末位置的项
public void DigSort(int[] s, int lastDig, int digLength)
{
//if (digLength - lastDig > 3)
// GetMid(ref s[lastDig], ref s[(lastDig + digLength) / 2], ref s[digLength]);
int i = lastDig, j = digLength;
int X = s[i];
while (i < j)
{
while (i < j && s[j] >= X) j--;
if (i < j) { s[i] = s[j]; i++; }
while (i < j && s[i] <= X) i++;
if (i < j) { s[j] = s[i]; j--; }
} //这里不难看出,跳出循环时,i=j,所以递归里没有出现j
s[i] = X;
if (lastDig < digLength)
{
DigSort(s, lastDig, i - 1);
DigSort(s, i + 1, digLength);
}
}
public void Cout()
{
for (int i = 0; i < im.Length; i++)
{
Console.Write(im[i] + ",");
}
}
public void GetMid(ref int x1, ref int x2, ref int x3)
{
//{ int temp = a[j]; a[j] = a[i]; a[i] = temp; }
if ((x1 <= x2 && x1 >= x3) || (x1 <= x3 && x1 >= x2))
return;
else if ((x2 <= x1 && x2 >= x3) || (x2 <= x3 && x2 >= x1))
{ int temp = x2; x2 = x1; x1 = temp; }
else
{ int temp = x3; x3 = x1; x1 = temp; }
}
}
}
该函数用于取某一区间头尾和中间项,得到3个项中的中间值,作为枢纽值进行快速排序
============================================================
因为在Unity里需要用到排序,测试了下发现用递归实现在unity里太慢了……一点都不快速=,=
偷懒是不好的,所以稍微改了一下。
所有的递归都可以用栈去存储数据从而做到循环代替递归。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CityBuild : MonoBehaviour
{
public void Start()
{
int[] im = { 70, 8, 6, 99, 4, 56, 45, 3, 56, 78, 1 };
QuickSort(im);
foreach (int x in im)
{
Debug.Log(x + ";");
}
}
public void QuickSort(int[] date)
{
Stack<int> indexStack;
int startIndex = 0;
int endIndex = date.Length - 1;
if (!(startIndex < endIndex))
return;
int digIndex = 0;
indexStack = new Stack<int>();
indexStack.Push(endIndex);
indexStack.Push(startIndex);
while (indexStack.Count != 0)
{
startIndex = indexStack.Pop();
endIndex = indexStack.Pop();
digIndex = partition(date, startIndex, endIndex);
if (startIndex < digIndex - 1)
{
indexStack.Push(digIndex - 1);
indexStack.Push(startIndex);
}
if (endIndex > digIndex + 1)
{
indexStack.Push(endIndex);
indexStack.Push(digIndex + 1);
}
}
}
private int partition(int[] date, int startIndex, int endIndex)
{
if (endIndex - startIndex > 3)
GetMid(ref date[startIndex], ref date[(startIndex + endIndex) / 2], ref date[endIndex]);
int i = startIndex, j = endIndex;
int X = date[i];
while (i < j)
{
while (i < j && date[j] >= X) j--;
if (i < j) { date[i] = date[j]; i++; }
while (i < j && date[i] <= X) i++;
if (i < j) { date[j] = date[i]; j--; }
} //这里不难看出,跳出循环时,i=j,所以递归里没有出现j
date[i] = X;
//这里返回一个i,此时i=j,用于入栈,注意先入end方便出栈
return i;
}
private void GetMid(ref int x1, ref int x2, ref int x3)
{
//{ int temp = a[j]; a[j] = a[i]; a[i] = temp; }
if ((x1 <= x2 && x1 >= x3) || (x1 <= x3 && x1 >= x2))
return;
else if ((x2 <= x1 && x2 >= x3) || (x2 <= x3 && x2 >= x1))
{ int temp = x2; x2 = x1; x1 = temp; }
else
{ int temp = x3; x3 = x1; x1 = temp; }
}
}