关于排序的一点点东西(2)

三、插入排序

我们怎么来实现一个插入排序呢

  1. 从第一个元素开始,该元素可以认为已经被排序
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
  5. 将新元素插入到该位置后
  6. 重复步骤2~5

当然有图就更直观啦

图片来源 维基百科
那么,我们来看看代码怎么实现:
void insertionSort(int arr[], int len)
{
    for (int i = 1; i < len; i++) {
        int temp = arr[i];
        int tempIndex = i;
        for (int j = i-1; j >= 0; j--) {
            if (arr[j] > temp)
            {
                arr[tempIndex] = arr[j];
                tempIndex = j;
            }
            else
            {
                break;
            }
        }
        arr[tempIndex] = temp;
    }
}
复制代码

这段代码还可以再精简一下。不过意思就是这个意思了。哈哈。

插入排序的比较是从有序序列的末尾开始,依次向前比较,相等元素的前后顺序是不会改变的。所以插入排序是稳定的。

四、快速排序

我们先来看一张图

图片来源 维基百科
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。

步骤为:

  1. 从数列中挑出一个元素,称为"基准"(pivot)
  2. 重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任何一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
  3. 递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。
  4. 递归到最底部时,数列的大小是零或一,也就是已经排序好了。这个算法一定会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

简单的说,就是不断的把数组分为左边(小于基准点)和右边(大于等于基准点)的两个子数组。

void quickSort(int arr[], int startIndex , int len){
    int left = startIndex;
    int temp ;
    for (int i = startIndex + len - 1; i > left; i--)
    {
        if (arr[i] < arr[startIndex])
        {
            for (int j = left; j < i ; j++) {
                left = j;
                if (arr[j] >= arr[startIndex])
                {
                    temp = arr[j];
                    arr[j] = arr[i];
                    arr[i] = temp;
                    break;
                }
            }
        }
    }
    temp = arr[startIndex];
    arr[startIndex] = arr[left];
    arr[left] = temp;
    if (left > startIndex) {
        quickSort(arr, startIndex, left - startIndex );
    }
    if (left + 1 < startIndex + len - 1) {
        quickSort(arr, left + 1, startIndex + len - left-1);
    }
}
复制代码

(写得不好,下次优化?)

快速排序是不稳定的排序。不稳定的时间点发生在中心交换的时候。例如5 3 3 4 3 8 9 10 11这个数组,最后5和3交换的时候,就打乱了3的顺序。

下次再见...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值