排序算法一览

排序作为最基础的算法,有选择排序,冒泡排序,插入排序,希尔排序,堆排序,快速排序,归并排续等,我会用c++写一下,欢迎交流~

排序算法的稳定性

如果在序列A中,Ai = Aj, 且i<j,经过排序之后,如果Ai和Aj的相对位置没有发生改变,则称这个算法是稳定的
比如在下表成绩排名中,老二和老四的成绩排名在排序前和排序后的相对位置没有改变,所以是这个排序是稳定的,如果改变了则是不稳定的

编号-序前姓名成绩编号-序后姓名成绩
1老大1351老五145
2老二1402老二140
3老三1303老四140
4老四1404老大135
5老五1455老三130

性能参数

时间性能
辅助空间
算法复杂性排序算法性能比较

选择排序

选择排序,是在每次循环中,找到一个最小值放在最左侧,时间复杂度为O(n^2)

void selectSort(int *a, int size)
{
    for (int i = 0; i < size-1; ++i) {
        //j每次循环一次,就选出剩余部分中最小的一个到次左边
        int n = i;
        for (int j = i+1; j < size; ++j) {
            if (a[n] > a[j])
                n = j;
        }
        
        //相对冒泡排序来说,交换次数较小
        if (n != i)
            std::swap(a[n], a[i]);
    }
}

冒泡排序

冒泡排序,是在每次循环中,将相邻的两个数比较大小,如果反序则交换位置,直到没有反序的位置为止,时间复杂度为O(n^2)

void bubbleSort(int *a, int size)
{
    for (int i = 0; i < size-1; i++) {
        //j每次循环一次,就交换相邻的两个字符
        int isTerminal = 0;
        for (int j = 0; j < size-1; j++) {
            if (a[j] > a[j+1]){
                std::swap(a[j], a[j+1]);
                isTerminal++;
            }
        }
        //在i<size-1时,如果序列两两比较时已经是有序的,没有发生过交换,则无需对i后续的遍历
        if (!isTerminal)
            break;
    }
}

插入排序

插入排序是对主循环中a[i]和a[j]比较,如果a[i]<a[j],则交换,然后对数组之前的j个元素比较大小两两交换

void insertSort(int *a, int size)
{
    for (int i = 1; i < size; i++) {
        for (int j = i-1; j>=0; j--) {
            if (a[j+1] < a[j])
                std::swap(a[j+1], a[j]);
            else
                break;  //j-1之前已经是有序的了,所以这时候直接break就可以了,能够节省比较次数
        }
    }
}

希尔排序

希尔排序是第一个时间复杂度为 O(n*log(n)) 的排序算法,主体思路是对相隔gap步长的元素比较大小,无序则进行排序。同插入排序有些相似,只是插入排序的步长为1,而希尔排序的步长是递减为1的。

void shellSort(int *a, int size)
{
    int gap = size;
    do{
        gap = gap/3 + 1;
        for (int i = gap; i < size; ++i) {
            for (int j = i-gap; j >=0 ; j-=gap) {
                if (a[j+gap] < a[j])
                    std::swap(a[j+gap], a[j]);
            }
        }
    }while (gap>1);
}

堆排序

(大顶堆)
堆排序就是将序列构造成完全二叉树,然后对每个根节点和他的叶子节点,满足根节点元素同时大于左右叶子节点,这样堆顶就是最大值

class heapSort{
public:
    heapSort(int *a, int size)
    {
        //构建大顶堆
        for (int i = size/2-1; i >= 0; i--) {
            heapJust(a, i, size-1);
        }

		//不断的将堆顶的值和末尾交换,并且重新构建大顶堆
        for (int i = size-1; i > 0; i--) {
            std::swap(a[0], a[i]);
            heapJust(a, 0, i-1);
        }
    }

    void heapJust(int *a, int s, int n) //s是树的第s层
    {
        int top = a[s];
        for (int i = s*2+1; i <= n; ) {
            if ((i < n) && (a[i] < a[i+1]))     //(i<n)是因为当i=n的时候,没有i++了
                i++;
            if (top < a[i]){
                a[s] = a[i];    //最大值始终给a[s]
                s = i;          //更新当前层的索引
                i = 2*i+1;      //
            }else
                break;
        }
        a[s] = top;
    }
};

快速排序

快速排序是目前最快的排序算法,整体思路是对一个序列选取一个基准值,通过比较大小将序列分为两个子序列,然后对每个子序列递归做同样的计算,最后得到有序序列.

class quickSort
{
public:
    quickSort(int* a, int size){
        qsort(a, 0, size-1);
    }

//通过Partition函数,找到序列的一个索引,将序列由一分二,然后对两个子序列分别递归调用
    void qsort(int* a, int low, int high)
    {
        int point;
        if (low < high){
            point = Partition(a, low, high);
            qsort(a, low, point-1);
            qsort(a, point+1, high);
        }
    }

//选择一个基准值,通常是序列第一个元素,对该序列从右至左选取第一个小于基准值的元素 right, 将该基准值与 right 交换位置.
// 然后对该序列从左至右选取第一个大于基准值的元素left,将该元素值left与序列最右元素交换.
    int Partition(int* a, int low, int high)
    {
        int point;
        point = a[low];	//这里选择序列第一个元素作为基准值
        while (low < high){
            while (low < high && a[high] >= point){ //>= 而不是>
                high--;
            }
            std::swap(a[low], a[high]);

            while (low < high && a[low] <= point){  //<= 而不是<
                low++;
            }
            std::swap(a[low], a[high]);
        }
        return low;
    }
};

归并排续

感觉归并排续和希尔排序有些相似.希尔排序是先对序列的大块排序,后对小块排序.归并排续是对大序列的每个小块先排序最后对大块排序.
在这里插入图片描述

                                                                           归并排序示意图

class mergeSort{
public:
    mergeSort(int* a, int size){
        if (size > 1){
            int *list1 = a;
            int size1 = size / 2;
            int *list2 = a + size / 2;
            int size2 = size - size1;

            mergeSort(list1, size1);
            mergeSort(list2, size2);

            merging(list1, size1, list2, size2, size);
        }
    }

    void merging(int *list1, int size1, int* list2, int size2, const int K_MAX_SIZE)
    {
        int i,j,k;
        i=j=k=0;
        int temp[K_MAX_SIZE];
        while (i < size1 && j < size2){
            if (list1[i] < list2[j]){
                temp[k++] = list1[i++];
            } else{
                temp[k++] = list2[j++];
            }
        }
        while (i < size1){
            temp[k++] = list1[i++];
        }
        while (j < size2){
            temp[k++] = list2[j++];
        }

        for (int m = 0; m < (size1+size2); ++m) {
            list1[m] = temp[m];
        }
    }
};

参考资料

  1. 牛客网视频
  2. 数据结构和算法(小甲鱼)–B站

代码下载

点击下载

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值