排序算法

排序算法是比较基础,且比较重要的数据结构内容。今天在这里简单总结一下基本原理、代码和注意事项,让自己有一个比较全面的了解,也能方便查看。
本文一共讲了选择排序、冒泡排序、快速排序、归并排序、插入排序、希尔排序、堆排序、桶排序、基数排序九种排序算法。

选择排序

循环中每次选择要排序记录中最小的一个和最前面的交换。换上n趟,就排好啦~

  • 时间复杂度:O(n^2)
    public int[] selectSort(int[] input) {

        for (int i = 0; i < input.length; i++) {
            int min = input[i];
            int index = i;
            for (int j = i + 1; j < input.length; j++) {
                if (input[j] < min) {
                    min = input[j];
                    index = j;
                }
            }
            int temp = input[i];
            input[i] = input[index];
            input[index] = temp;
        }
        return input;
    }

冒泡排序

一趟排序中依次比较相邻的两个,如果前面的大于后面的就交换,这样一趟下来最大的一定会到最后一位。然后运行n趟,这整个为n的记录就排好序了。

  • 时间复杂度: O(n^2)
    public int[] bubbleSort(int[] input) {
        for (int i = 0; i < input.length; i++) {
            for (int j = 0; j < input.length - 1 - i; j++) {
                if (input[j] > input[j + 1]) {
                    int temp = input[j];
                    input[j] = input[j + 1];
                    input[j + 1] = temp;
                }
            }
        }
        return input;
    }

快速排序

每一次排序都会把待排序的记录分成两部分,其中一部分均比另一部分小,然后再对这两两部分分别排序,直到完全有序。

  • 具体做法:选择记录中第一个数字作为关键字,将传入的左边界和右边界作为左右指针,先循环减少右指针寻找右边小于关键字的挪到左指针的位置,然后再循环增加左指针从左边找大于关键字的挪到右指针位置,直到左指针等于右指针,然后将关键字赋到这个位置。然后再递归调用这两部分。直到结束。
  • 时间复杂度:O(nlogn)
  • 注意:排序算法被认为是相同时间复杂度里平均性能最好的。如果序列基本有序会退化为冒泡排序,时间复杂度为O(n^2)
    public int[] quickSort(int[] input, int low, int height) {
        if (low >= height) {
            return null;
        }

        int left = low;
        int right = height;
        int key = input[left];
        while (left < right) {
            while (left < right && input[right] >= key) {
                right--;
            }
            input[left] = input[right];
            while (left < right && input[left] <= key) {
                left++;
            }
            input[right] = input[left];
        }
        input[left] = key;

        quickSort(input, low, left - 1);
        quickSort(input, right + 1, height);

        return input;
    }

归并排序

采用递归的方法,将待排序的记录分成几个有序的小部分,然后再进行合并。

  • 具体做法:递归的将记录分为最小部分,然后再从合并中排序。合并的过程中,先从两个的左边开始比较,如果较小就放到临时数组里,直到有一方空了,再把另一个数组的剩余部分全部放进临时数组里。然后再把临时数组重新放到原数组。最后合并为一个完全有序的记录。
  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(n)
    public void mergeSort(int[] input, int low, int height) {
        if (low < height) {
            int mid = (low + height) / 2;
            mergeSort(input, low, mid);
            mergeSort(input, mid + 1, height);
            merge(input, low, height);
        }
    }

    public void merge(int[] input, int left, int right) {
        int[] temp = new int[input.length];
        int mid = (left + right) / 2;
        int index = left;

        int i = left;
        int j = mid + 1;
        while (i <= mid && j <= right) {
            if (input[i] < input[j]) {
                temp[index++] = input[i++];
            } else {
                temp[index++] = input[j++];
            }
        }

        while (i <= mid) {
            temp[index++] = input[i++];
        }
        while (j <= right) {
            temp[index++] = input[j++];
        }

        for (int a = left; a <= right; a++) {
            input[a] = temp[a];
        }
    }

直接插入排序

将一个记录插入到已经排好序的有序表中,得到一个新的、记录数增一的有序表。

  • 形象描述:就像打牌的时候,我们每抓一张牌都会把这张牌插入到已经排好顺序的牌里面。
  • 具体做法:外层循环从1到n-1。内层循环查看当前数字是否比前一个数字小,如果大的话就跳过,如果小就要循环已排好序数列,然后将当前数字插入到合适位置。
  • 时间复杂度:O(n^2)
  • 注意:在基本有序情况下,直接插入算法是最快的排序算法,时间复杂度为O(n)
    public int[] straightInsertionSort(int[] input) {
        for (int i = 1; i < input.length; i++) {
            int temp = input[i];
            int j;
            for (j = i - 1; j >= 0 && temp < input[j]; j--) {
                input[j + 1] = input[j];
            }
            input[j + 1] = temp;
        }
        return input;
    }

希尔排序

先将整个待排序记录分为若干子序列分别进行直接插入排序,待整个序列中的记录基本有序时,再进行一次直接插入排序。

  • 具体实现:先选择插入的距离为length/2完成第一次插入排序,然后再从原来的基础上/2,最后当距离变成1的时候就变成了直接插入排序。
  • 时间复杂度:不好说,但肯定比直接插入排序智能点。
    public int[] shellSort(int[] input) {
        int dk = input.length / 2;
        while (dk > 0) {
            for (int i = dk; i < input.length; i++) {
                int temp = input[i];
                int j;
                for (j = i - dk; j >= 0 && temp < input[j]; j -= dk) {
                    input[j + dk] = input[j];
                }
                input[j + dk] = temp;
            }
            dk /= 2;

        }
        return input;
    }

堆排序

先将记录转化为最大堆或者最小堆,然后不断地将第一个数字拿出来存储,然后调整堆,最后堆为空的时候,排序完成。

  • 具体视线:首先生成堆,然后把堆的第一个元素和最后一个元素交换,减少堆的长度。然后重新把被破坏了的堆重新调整成堆。然后再完成交换,直到结束。
  • 时间复杂度:O(nlogn)
    public int[] heapSort(int[] input) {
        buildHeap(input);

        for (int i = input.length - 1; i >= 0; i--) {
            int t = input[i];
            input[i] = input[0];
            input[0] = t;

            adjustHeap(input, 0, i);
        }
        return input;
    }

    private void buildHeap(int[] input) {
        for (int i = (input.length - 1) / 2; i >= 0; i--) {
            adjustHeap(input, i, input.length);
        }
    }

    private void adjustHeap(int[] input, int s, int length) {
        int temp = input[s];
        int child = 2 * s + 1;
        while (child < length) {
            if (child + 1 < length && input[child + 1] > input[child]) {
                child++;
            }
            if (input[child] > input[s]) {
                input[s] = input[child];
                input[child] = temp;
                s = child;
                child = 2 * s + 1;
            } else {
                break;
            }
        }
    }

桶排序

新建一个容量为最大数字+1个的数组空间。然后把每个数直接放到该数组与自己对应的地方,然后按次序拿出来就好了。

  • 时间复杂度:O(n)
  • 注意:考虑负数和有相同数字的情况,本程序没考虑。
    public int[] bucketSort(int[] input, int max) {
        int[] temp = new int[max + 1];
        for (int i = 0; i < input.length; i++) {
            temp[input[i]] = input[i];
        }
        int index = 0;
        for (int i = 0; i < max + 1; i++) {
            if (temp[i] != 0) {
                input[index++] = temp[i];
            }
        }
        return input;
    }

基数排序

分别以各位数字进行桶排序,然后按顺序取出,遍历完所有位遍完成排序。

  • 具体实现:先建立一个二维数组,然后将个位上相同的数字放进同一个桶,然后依次取出放回原数组,这样就实现了个位上的有序,然后百位,千位,最后遍历完成所有位即完成排序。
  • 时间复杂度:O(d(n+rd))
  • 空间复杂度:O(rd)
  • 注意:要考虑存在负数的情况。本程序里没有考虑。
    public int[] radixSort(int[] input, int max) {
        int[][] temp = new int[10][input.length];
        int[] num = new int[10];

        int index = 1;
        int n = 1;
        while (index <= max) {
            for (int i = 0; i < input.length; i++) {
                int wei = input[i] / n % 10;
                temp[wei][num[wei]++] = input[i];
            }
            int count = 0;
            for (int i = 0; i < 10; i++) {
                for (int j = 0; j < input.length; j++) {
                    if (temp[i][j] == 0) {
                        break;
                    } else {
                        input[count++] = temp[i][j];
                    }
                }
            }
            for (int i = 0; i < 10; i++) {
                num[i] = 0;
                for (int j = 0; j < input.length; j++) {
                    temp[i][j] = 0;
                }
            }

            index++;
            n *= 10;
        }
        return input;
    }

就酱~

欢迎关注【Funny新青年】微信公众号~

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

推荐阅读更多精彩内容

  • 概述:排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    每天刷两次牙阅读 3,727评论 0 15
  • 概述排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的...
    Luc_阅读 2,253评论 0 35
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,164评论 0 52
  • 这本书,通过以下几个步骤告诉我们如何写作:首先应当做写作前的准备,其次应该僻静写作,最后写作要注重细节。 一、写作...
    夜空中最亮的那颗星星阅读 208评论 3 0