您的位置:首页 > 移动开发 > Unity3D

各种排序算法

2016-04-12 18:08 441 查看
快速排序

快速排序作为复杂排序中最好用的排序算法,作为程序员是必须要掌握的。

先说说排序算法的思路,我们对照着下图慢慢说。

比如我们有一个数组:

角标 0 1 2 3 4 5 6
数组 6 4 7 3 9 2 8


我们随便选择一个值为基准数X,我们这里选择0位置的数字6,X=6。然后我们创建两个游标 i和j 。因为我们是要对整个数组进行排序,那么我们就给游标一个初始值: i = 0 ,j = 6 。

初始化的工作完成了,接下来是排序的核心内容了。

第一步,把比基准数大的数放在右边,把比基准数小的数放左边。

我们从右边开始向左移动游标j,选择一个比基准数小的数放到基准数的位置。当j为5的时候,发现2小于等于6。

角标 0 1 2 3 4 5 6
数组 2 4 7 3 9 ? 8


接下来我们从左边开始向右移动游标i,选择一个比基准数大的数放到之前空去来的位置。当i移动到2的时候,发现7大于等于6。

角标 0 1 2 3 4 5 6
数组 2 4 ? 3 9 7 8
然后我们又由右向左移动j,找一个大于6的值。是不是有种荡秋千的感觉

。我们发现了当j为3的时候,9大于等于6。

角标 0 1 2 3 4 5 6
数组 2 4 3 ? 9 7 8
之后我们向右移动i,当为3的时候,i就和j相等了!我们把基准数赋值给这个‘?’,第一步就完成了!


角标 0 1 2 3 4 5 6
数组 2 4 3 6 9 7 8
我们可以发现比基准数小的数在基准数的左边,比基准值大的数在基准数的右边,而基准数的位置就是最终排序结果的位置。
第二步,我们把基准数左边和右边都提取出来,得到两个小的集合。

角标 0 1 2
数组 2 4 3



角标 0 1 2
数组 9 7 8

我们把这两个数组分别使用第一步的方法,接着分下去。分到的集合继续分下去,直到不能分下去为止。因为这种分割的方法,我称它为二分法。

我找到了一幅图,可能会比较形象,容易大家理解。



想来大家对快速排序的思路比较清晰了。我们使用代码来实现这个思路:

/// <summary>
/// 快速排序
/// </summary>
/// <param name="arrayAway">需要排序的集合</param>
/// <param name="left">开始位置的角标</param>
/// <param name="right">结束位置的角标</param>
public void QuickSort( int[] arrayAway, int left, int right)
{
if (left < right) //左边必须小于右边
{
int X = arrayAway[left];
int i = left;
int j = right;

while (i < j)
{
//从右至左移动,找到一个比基准数小的数,把这个数放到基准数的位置。
while (i < j)
{
if (arrayAway[j] <= X)
{
arrayAway[i] = arrayAway[j];
break;
}
else
{
j--;
}
}

//从左至右移动,找到一个比基准数大的数,把这个数放到之前空出的位置(角标为j的位置)上。
while (i < j)
{
if (arrayAway[i] >= X)
{
arrayAway[j] = arrayAway[i];
break;
}
else
{
i++;
}
}
}
//第一步的最后,将基准值放到i=j的位置。
arrayAway[i] = X;

//第二步,我们递归这个方法
QuickSort( arrayAway, left, i - 1);
QuickSort( arrayAway, i + 1, right);
}
}

怎么样?是不是很简单!大家去试试吧!


直接插入排序

还是先讲讲思路,我们从数组第二个数据开始遍历,将这个数和他前面的数进行比较,如果前面的数大于这个数,就将前面数的位置向后移动一位,不大于就将这个数放到前面位置的后面一位(原地不动),遍历完了没有插入就放到角标为0的位置。

思路说的有点绕,我们以一个实例来详细说明。

角标 0 1 2 3 4 5 6
数组 6 4 7 3 9 2 8


我们从角标为1的位置,这个位置的数是4,拿他和前面比较,6大于4,把6移动到角标1的位置,然后继续遍历,遍历完没有插入,把这个数放到角标为0的位置。

角标 0 1 2 3 4 5 6
数组 4 6 7 3 9 2 8
我们继续选择2号位置的7,将7和前面的数比较,6小于7,那么7的位置不变。

我们选择角标为3的数3,拿它和前面的数比较,3小于4、6、7,7、6、4依次向后移动一位,3没有插入,我们把他放到角标为0的位置。

角标 0 1 2 3 4 5 6
数组 3 4 6 7 9 2 8
说到这,其实思路已经很清楚了,也没有再继续啰嗦的必要了。我们使用代码来实现这个思路。

void InsertSort(int[] arrayAway)
{
for (int i = 1; i < arrayAway.Length; i++ )
{
int X = arrayAway[i];
bool flag = false;
//将X和前面相比较,如果值大于X,向后移动一位,如果小于,就讲X放到前面值得后一位(也就是当前X的位置)
for (int j = i - 1; j >= 0;j-- )
{
if (arrayAway[j] > X)
{
arrayAway[j + 1] = arrayAway[j];
}
else
{
arrayAway[j + 1] = X;
flag = true;
break;
}
}

if (!flag) arrayAway[0] = X;
}
}


冒泡排序

先说说思路。从右往左相邻的两个数两两比较,把小的数放前,一次循环,把最小的数放到最前面。然后将除了最前面一个数从右至左两两比较,确定第二小的数,这样依次从前往后确定数的位置,实现排序。我们来看图说话:



从角标为5的位置开始,1、3比较,1小,1放前面,然后1、6比较,1小,放前面,依次这样,将1放到最前面。就实现了最小值放最前面。

我们用代码来实现这个思路:

void BubblingSort(int[] arrayAway)
{
for (int i = 0; i < arrayAway.Length;i++)
{
int X = 0; //交换位置的容器
for (int j = arrayAway.Length - 1; j > 0;j--)
{
//如果前面的大于后面的,就交换位置
if(arrayAway[j-1]>arrayAway[j]){

X = arrayAway[j];
arrayAway[j] = arrayAway[j - 1];
arrayAway[j - 1] = X;
}
}
}
}

来看一张图便于理解冒泡排序:



简单选择排序

简单选择排序和冒泡排序有点相似,都是通过循环来找到最大数/最小数,然后找到第二大/小的数,不同的是冒泡排序是在不断的交换来事件排序,而选择排序是直接在里面找到我们想要的数。






以0号位置的数42为基准数,假设他为最小值,遍历它后面的数,如果有比他小的数就记录下来,和0号位置的42交换,那么就找到了第一小的数。接着从1号位置开始,假设为最小值,遍历后面的数找到第二小的数,以此类推实现排序。

我们用代码来实现这种排序:

void SelectSort(int[] arrayAway)
{
for (int i = 0; i < arrayAway.Length - 1;i++ )
{
int min = arrayAway[i];
int minIndex = i;
for (int j = i + 1; j < arrayAway.Length;j++)
{
if(arrayAway[j]<min){
min = arrayAway[j] ;
minIndex = j;
}
}

if(minIndex != i){
int temp = arrayAway[i];
arrayAway[i] = arrayAway[minIndex];
arrayAway[minIndex] = temp;
}
}
}


简单选择排序示意图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息