排序

文中图片均来自于网络
冒泡排序

冒泡排序
template <class T>
void bubbleSort(T arr[], int len) {
    for (int i = 0; i < len - 1; ++i) { //  n-1 步
        for (int j = 0; j < len - i - 1; ++j) { // n-1, n-2 ,n - 3, 1
            if (arr[j] > arr[j + 1]) {
                // 交换 一次交换是三次赋值
                std::swap(arr[j], arr[j + 1]);
            }
        }
    }
}

时间复杂度: O(n^2), 属于稳定排序

优化1 (优化外层循环):设置交换的flog

template <class T>
void bubbleSort(T arr[], int len) {

    for (int i = 0; i < len - 1; ++i) { //  n-1 步
        bool change_flog = false;
        for (int j = 0; j < len - i - 1; ++j) { // n-1, n-2 ,n - 3, 1
            if (arr[j] > arr[j + 1]) {
                // 交换 一次交换是三次赋值
                std::swap(arr[j], arr[j + 1]);
                change_flog = true;
            }
        }
        if (!change_flog) {
            break;
        }
    }
}


优化2(优化内层循环):记住最后一次交换发生的位置lastExchange

template <class T>
void bubbleSort(T arr[], int len) {
    int last_pos = 0;
    int k = len - 1;
    for (int i = 0; i < len - 1; ++i) { //  n-1 步
        bool change_flog = false;
        for (int j = 0; j < k; ++j) { // n-1, n-2 ,n - 3, 1
            if (arr[j] > arr[j + 1]) {
                // 交换 一次交换是三次赋值
                std::swap(arr[j], arr[j + 1]);
                change_flog = true;
                last_pos = j;
            }
        }
        k = last_pos;
        if (!change_flog) {
            break;
        }
    }
}

选择排序

选择排序
template <class T>
void selectSort(T arr[], int len) {
    for (int i = 0; i < len; ++i) {
        int min = i;
        for (int j = i + 1; j < len; ++j) {
            if (arr[min] > arr[j]) {
                min = j;
            }
        }
        //一次交换
        swap(arr[i], arr[min]);
    }
}

时间复杂度: O(n^2), 属于稳定排序

优化 : 一边最大,一边最小

template <class T>
void selectSort(T arr[], int len) {
    int left = 0;
    int right = len - 1;
    while (left < right) {
        int min = left;
        int max = right;
        for (int i = left; i <= right; i++) {
            if (arr[i] < arr[min])
                min = i;
            if (arr[i] > arr[max])
                max = i;
        }
        //考虑修正的情况,最大值在最小位置,最小值在最大位置。
        swap(arr[max], arr[right]);

        if (min == right) {
            min = max;
        }
        swap(arr[min], arr[left]);
        left++;
        right--;
    }
}

插入排序

前身:

template <class T>
void insertSort(T arr[], int len) {
    for (int i = 1; i < len; ++i) {
        for (int j = i; j > 0 ; --j) {
            if(arr[j] < arr[j - 1]){
               swap(arr[j], arr[j - 1]);
            }else {
                break;
            }
        }
    }
}

时间复杂度:O(n^2)

优化:上面得排序代码交换位置很多,我们优化减少交换的次数。每一次先拿出当前位置作为临时值,然后在遍历和前一个数比较,如果前面一个数大于临时值,那么将当前位置的值赋值为前面一个数的值,反正则记录位置,跳出遍历,最后将那个记录位置赋值为记录的临时值即可。原理就像是扑克牌一样,找个合适的位置,然后插入。

插入排序
插入排序优化
template <class T>
void insertSort(T arr[], int len) {
    int j, i;
    for (i = 1; i < len; ++i) {// O(n)
        // 当前的位置
        int tmp = arr[i];
        for (j = i; j > 0; --j) {
            if(arr[j - 1] > tmp){
              arr[j] = arr[j - 1];
            }else {
                break;
            }
        }
        // 插入合适的位置
        arr[j] = tmp;
    }
}

优化之后的插入排序最好的情况(接近排好序的)时间复杂度是O(n),这个是很强的。 属于稳定排序

希尔排序

我的理解希尔排序是一个优化的插入排序,插入排序在接近排好序的数据进行排序效率是非常高的,所以希尔排序主要就是进行将一个数据紊乱的数组通过插入排序给尽量的排好序。 属于不稳定排序。
思想:分治

希尔排序
template <class T>
void shellInsertSort(T arr[], int len) {
    int increment = len / 2;
    int i, j, k;
    while (increment >= 1) {
        for (i = 0; i < increment; ++i) {
            for (j = i + increment; j < len; j += increment) {
                int tmp = arr[j];
                for (k = j; k > i ; k -= increment) {
                    // 往后逻动
                    if(arr[k - increment] > tmp){
                        arr[k] = arr[k - increment];
                    }else{
                        break;
                    }
                }
                arr[k] = tmp;
            }
        }
        increment /= 2;
    }
}

如果一个组数据接近排好序的,那么用希尔排序的效率将会非常高。

归并排序

参考: https://www.cnblogs.com/chengxiao/p/6194356.html

归并排序采用分治的思想进行排序(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
如下图所示:

归并排序

归并排序合并:

归并排序合并

void merge(int arr[], int left, int mid, int right, int temp[]) {
    int i = left;//左序列指针
    int j = mid + 1;//右序列指针
    int t = 0;//临时数组指针
    while (i <= mid && j <= right) {
        if (arr[i] <= arr[j]) {
            temp[t] = arr[i];
            i++;
        } else {
            temp[t] = arr[j];
            j++;
        }
        t++;
    }
    while (i <= mid) {//将左边剩余元素填充进temp中
        temp[t] = arr[i];
        t++;
        i++;
    }
    while (j <= right) {//将右序列剩余元素填充进temp中
        temp[t] = arr[j];
        t++;
        j++;
    }
    t = 0;
    //将temp中的元素全部拷贝到原数组中
    while (left <= right) {
        arr[left] = temp[t];
        left++;
        t++;
    }
}

void mergeSort_(int arr[], int left, int right, int temp[]) {
    if (left < right) {
        int mid = (left + right) >> 1;
        mergeSort_(arr, left, mid, temp);//左边归并排序,使得左子序列有序
        mergeSort_(arr, mid + 1, right, temp);//右边归并排序,使得右子序列有序
        merge(arr, left, mid, right, temp);//将两个有序子数组合并操作
    }
}

void mergeSort(int arr[], int len) {
    int temp[len];//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
    mergeSort_(arr, 0, len - 1, temp);
}

时间复杂度:O(N*logN),稳定排序

快速排序

参考: https://blog.csdn.net/MoreWindows/article/details/6684558

快速排

使用挖坑填数+分治法的思想。

比如上图所示的3 6 5 9 7 1 8 2 4

取区间第一个数位基准,初始的时候,i=0,j=8,temp=arr[i]=3,可以理解将arr的第0个位置拿出来,挖了个坑,然后从j开始从前找到一个比temp小的数,也就是2,这个时候j=7,将2填到i的位置,也就是0的位置,i++。这个时候j=7的就被挖了出来就空了,需要一个数填,就需要从i=1开始找一个比temp大的数填到j=7的位置,找到了数值填之后,在重复找数填。

代码如下:


int partition_(int s[], int l, int r) //返回调整后基准数的位置
{
    int i = l, j = r;
    int x = s[l]; //s[l]即s[i]就是第一个坑
    while (i < j) {
        // 从右向左找小于x的数来填s[i]
        while (i < j && s[j] >= x)
            j--;
        if (i < j) {
            s[i] = s[j]; //将s[j]填到s[i]中,s[j]就形成了一个新的坑
            i++;
        }

        // 从左向右找大于或等于x的数来填s[j]
        while (i < j && s[i] < x)
            i++;
        if (i < j) {
            s[j] = s[i]; //将s[i]填到s[j]中,s[i]就形成了一个新的坑
            j--;
        }
    }
    //退出时,i等于j。将x填到这个坑中。
    s[i] = x;

    return i;
}

void quickSort_(int s[], int l, int r) {
    if (l >= r) {
        return;
    }
    int i = partition_(s, l, r);//先成挖坑填数法调整s[]
    quickSort_(s, l, i - 1); // 递归调用
    quickSort_(s, i + 1, r);
}

// 快速排序
void quickSort(int arr[], int len) {
    quickSort_(arr, 0, len - 1);
}

时间复杂度: O(N*logN),不稳定排序

堆排序

  1. 构造初始堆。将给定无序序列构造成一个最大堆(一般升序采用最大堆,降序采用最小堆)。
  2. 将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。
第一步

第二步

#include <iostream>

/**
 * 调整大根堆
 * @param arr
 * @param index
 * @param len
 */
static void adjustHeap(int *array, int k, int len) {
    //是否到底
    while (k * 2 + 1 < len) {
        //默认最大值为左孩子
        int max = k * 2 + 1;
        //有右孩子并且大于左孩子
        if (max + 1 < len && array[max] < array[max + 1]) {
            max = max + 1;
        }
        if (array[k] > array[max]) {
            break;
        }
        //交换
        std::swap(array[k], array[max]);
        k = max;
    }
}


static void heapSoft(int *arr, int len) {
    //1.构建大顶堆
    // 从最后一个不是叶子节点的节点,开始调整为大根堆
    for (int i = len / 2 - 1; i >= 0; --i) {
        adjustHeap(arr, i, len);
    }
    //2. 第一个与最后一个交换,然后在调整为大根堆,但是不考略最后一个了
    for (int i = len - 1; i > 0; --i) {
        std::swap(arr[0], arr[i]);
        adjustHeap(arr, 0, i);//对第0个数据调整,最后一个不考略
    }
}

时间复杂度:O(nlogn) ,不稳定排序.
参考: https://www.cnblogs.com/chengxiao/p/6129630.html

本文图片均来自于网络。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 该系列文章主要是记录下自己暑假这段时间的学习笔记,暑期也在实习,抽空学了很多,每个方面的知识我都会另起一篇博客去记...
    Yanci516阅读 12,175评论 6 19
  • 概述 因为健忘,加上对各种排序算法理解不深刻,过段时间面对排序就蒙了。所以决定对我们常见的这几种排序算法进行统一总...
    清风之心阅读 685评论 0 1
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,164评论 0 52
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好...
    依依玖玥阅读 1,239评论 0 2
  • 忙碌的一天开始了,晚上下班还是很期待和孩子们的交流互动,儿子今天参与了升旗仪式,很为你感到高兴,还记得你知道...
    温温温温渔阅读 277评论 0 1