各种排序算法

快速排序

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

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

比如我们有一个数组:

角标 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;
            }
        }
    }

简单选择排序示意图:






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值