(07)排序算法

排序也就是使集合中的元素有序化,他是常见的计算机操作之一,主要介绍几种经典的排序方法:冒泡排序,插入排序,快速排序,选择排序

一,冒泡排序

冒泡排序是一种简单的排序算法,就是将一个列表种的两个元素进行比较,并将最小元素交换到顶部,从最底部元素开始比较,两个元素种较小的会冒到顶部,较大的会沉到底部,该过程会重复执行,直到所有元素都被排序。     

第一次比较完,最后一个数一定是最大的值,所以第二趟比较的时候最后一个数不参与较。第二趟比较完成后,倒数第二个数也一定是数组中第二大的数,所以第三趟比较的时候最后两个数不参与比较。依次类推,每一趟比较次数-1;

N个数字要排序完成,总共进行N-1趟排序,每i趟的排序次数为(N-i)次,所以可以用双重循环语句,外层控制循环多少趟,内层控制每一趟的循环次数,即

int a[]={16,25,9,90,23};                                                                //N个数字来排队,两两相比小靠前

        for (int i=0;i<a.length-1;i++){                                                //外层循环N-1

            for (int j=0;j<a.length-1-i;j++){                                          //内存循环N-1-i

                if(a[j]>a[j+1]){

                    int tmp=a[j+1];

                    a[j+1]=a[j];

                    a[j]=tmp;

                }

            }

        }

        for (int i=0;i<a.length;i++){

            System.out.println(a[i]+" ");

        }

冒泡排序的优点:每进行一趟排序,就会少比较一次,因为每进行一趟排序都会找出一个较大值。如上例:第一趟比较之后,排在最后的一个数一定是最大的一个数,第二趟排序的时候,只需要比较除了最后一个数以外的其他的数,同样也能找出一个最大的数排在参与第二趟比较的数后面,第三趟比较的时候,只需要比较除了最后两个数以外的其他的数,以此类推…也就是说,没进行一趟比较,每一趟少比较一次,一定程度上减少了算法量。

二,插入排序

假设有一个已经有序的数据数列,要求在这个已经排好序的数据序列里插入一个数,但要求插入后数据仍然有序,类似于玩扑克的时候,玩家每抓到一张牌,都插入到手里已有的牌里,使之从小到大排好序。                        将要排序的是一个乱的数组int [] a={3,1,2,4,3},在未知后续数值情况下

  第一趟排序

我们把第一个数当作已经排好序的,然后用数组的第二个数跟第一个数想比                                                          如果第二个数比第一个大,就不管他                                                                                                                      如果比第一个数小,那就让大的往后排一位,小的排到第一个的位置,排完结果使{1,3}

  第二趟排序

用数组的第三个数与已是有序的数据{1,3}(刚才在第一趟排的)比较                                                                        如果比第二个大,那就不管它,如果比第2个小,那就将第2个往后退一个位置,再让第三个数和第1个比较        如果第三个数比第一个大,那么将第三个数插入到第2个的位置上                                                                          如果第三个数比第一个小,那么将第1个数后退一步,将第三个数插入到第1个的位置上

  代码

n个数排序,需要n-1趟排序,第一个表示已经有序

public static void main(String[] args) {

      //插入排序

        int temp;

        int [] a={3,1,2,6,5};

        //外层循环控制排序的趟数,i从1开始是因为将第0位看成有序的了

        for (int i=1;i<a.length;i++){

            temp=a[i];

            //如果第二位比第一个小,进入第二趟循环

            while (i>0 && a[i-1]>temp){

                //将第一个数值赋值到第二位置上

                a[i]=a[i-1];

                //不断的向前比较

                i--;

            }

            a[i]=temp;//推出循环则说明找到合适位置

        }

        //数组a遍历输出

        for (int i=0;i<a.length;i++){

            System.out.print(a[i]+"  ");

        }

    }

快速排序

有没有既不浪费空间又可以快一点的排序算法呢?那就是“快速排序”啦!光听这个名字是不是就觉得很高端呢。假设我们现在对“6 1 2 7 9 3 4 5 10 8”这个10个数进行排序。首先在这个序列中随便找一个数作为基准数(不要被这个名词吓到了,就是一个用来参照的数,待会你就知道它用来做啥的了)。为了方便,就让第一个数6作为基准数吧。接下来,需要将这个序列中所有比基准数大的数放在6的右边,比基准数小的数放在6的左边,类似下面这种排列:

3 1 2 5 4 6 9 7 10 8

在初始状态下,数字6在序列的第1位。我们的目标是将6挪到序列中间的某个位置,假设这个位置是k。现在就需要寻找这个k,并且以第k位为分界点,左边的数都小于等于6,右边的数都大于等于6。想一想,你有办法可以做到这点吗?

方法其实很简单:分别从初始序列“6 1 2 7 9 3 4 5 10 8”两端开始“探测”。先从找一个小于6的数,再从找一个大于6的数,然后交换他们。这里可以用两个变量i和j,分别指向序列最左边和最右边。我们为这两个变量起个好听的名字“哨兵i”和“哨兵j”。刚开始的时候让哨兵i指向序列的最左边(即i=1),指向数字6。让哨兵j指向序列的最右边(即=10),指向数字。

首先哨兵j开始出动。因为此处设置的基准数是最左边的数,所以需要让哨兵j先出动,这一点非常重要(请自己想一想为什么)。哨兵j一步一步地向左挪动(即j–),直到找到一个小于6的数停下来。接下来哨兵i再一步一步向右挪动(即i++),直到找到一个数大于6的数停下来。最后哨兵j停在了数字5面前,哨兵i停在了数字7面前。

现在交换哨兵i和哨兵j所指向的元素的值。交换之后的序列如下:

6 1 259 3 4710 8

到此,第一次交换结束。接下来开始哨兵j继续向左挪动(再友情提醒,每次必须是哨兵j先出发)。他发现了4(比基准数6要小,满足要求)之后停了下来。哨兵i也继续向右挪动的,他发现了9(比基准数6要大,满足要求)之后停了下来。此时再次进行交换,交换之后的序列如下:

6 1 2 54397 10 8

第二次交换结束,“探测”继续。哨兵j继续向左挪动,他发现了3(比基准数6要小,满足要求)之后又停了下来。哨兵i继续向右移动,糟啦!此时哨兵i和哨兵j相遇了,哨兵i和哨兵j都走到3面前。说明此时“探测”结束。我们将基准数6和3进行交换。交换之后的序列如下:

31 2 5 469 7 10 8

到此第一轮“探测”真正结束。此时以基准数6为分界点,6左边的数都小于等于6,6右边的数都大于等于6。回顾一下刚才的过程,其实哨兵j的使命就是要找小于基准数的数,而哨兵i的使命就是要找大于基准数的数,直到i和j碰头为止。

OK,解释完毕。现在基准数6已经归位,它正好处在序列的第6位。此时我们已经将原来的序列,以6为分界点拆分成了两个序列,左边的序列是“3 1

2 5 4”,右边的序列是“9 7 10

8”。接下来还需要分别处理这两个序列。因为6左边和右边的序列目前都还是很混乱的。不过不要紧,我们已经掌握了方法,接下来只要模拟刚才的方法分别处理6左边和右边的序列即可。现在先来处理6左边的序列现吧。

左边的序列是“3 1 2 5 4”。请将这个序列以3为基准数进行调整,使得3左边的数都小于等于3,3右边的数都大于等于3。好了开始动笔吧

public static void main(String[] args) {

        int[] arr = { 49, 38, 65, 97, 23, 22, 76, 1, 5, 8, 2, 0, -1, 22 };

        quickSort(arr, 0, arr.length - 1);

        System.out.println("排序后:");

        for (int i : arr) {

            System.out.println(i);

        }

    }

    private static void quickSort(int arr[], int low, int high) {

        int i,j,temp,t;

        if(low>high){

            return;

        }

        i=low;

        j=high;

        //temp就是基准位

        temp = arr[low];

        while (i<j) {

            //先看右边,依次往左递减

            while (temp<=arr[j]&&i<j) {

                j--;

            }

            //再看左边,依次往右递增

            while (temp>=arr[i]&&i<j) {

                i++;

            }

            //如果满足条件则交换

            if (i<j&&arr[i]>arr[j]) {

                t = arr[j];

                arr[j] = arr[i];

                arr[i] = t;

            }

        }

        //最后将基准为与i和j相等位置的数字交换

        arr[low] = arr[i];

        arr[i] = temp;

        //递归调用左半数组

        quickSort(arr, low, j-1);

        //递归调用右半数组

        quickSort(arr, j+1, high);

}


选择排序

a) 原理:每一趟从待排序的记录中选出最小的元素,顺序放在已排好序的序列最后,直到全部记录排序完毕。也就是:每一趟在n-i+1(i=1,2,…n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。基于此思想的算法主要有简单选择排序、树型选择排序和堆排序。(这里只介绍常用的简单选择排序)

b) 简单选择排序的基本思想:给定数组:int[] arr={里面n个数据};第1趟排序,在待排序数据arr[1]~arr[n]中选出最小的数据,将它与arrr[1]交换;第2趟,在待排序数据arr[2]~arr[n]中选出最小的数据,将它与r[2]交换;以此类推,第i趟在待排序数据arr[i]~arr[n]中选出最小的数据,将它与r[i]交换,直到全部排序完成。

c) 举例:数组 int[] arr={5,2,8,4,9,1};

-------------------------------------------------------

第一趟排序: 原始数据:5  2  8  4  9  1

最小数据1,把1放在首位,也就是1和5互换位置,

排序结果:1  2  8  4  9  5

-------------------------------------------------------

第二趟排序:

第1以外的数据{2  8  4  9  5}进行比较,2最小,

排序结果:1  2  8  4  9  5

-------------------------------------------------------

第三趟排序:

除1、2以外的数据{8  4  9  5}进行比较,4最小,8和4交换

排序结果:1  2  4  8  9  5

-------------------------------------------------------

第四趟排序:

除第1、2、4以外的其他数据{8  9  5}进行比较,5最小,8和5交换

排序结果:1  2  4  5  9  8

-------------------------------------------------------

第五趟排序:

除第1、2、4、5以外的其他数据{9  8}进行比较,8最小,8和9交换

排序结果:1  2  4  5  8  9

-------------------------------------------------------

注:每一趟排序获得最小数的方法:for循环进行比较,定义一个第三个变量temp,首先前两个数比较,把较小的数放在temp中,然后用temp再去跟剩下的数据比较,如果出现比temp小的数据,就用它代替temp中原有的数据。具体参照后面的代码示例,相信你在学排序之前已经学过for循环语句了,这样的话,这里理解起来就特别容易了


public static void main(String[] args) {

        int [] arr={6,8,1,15,92,45,2,80};

        System.out.print("没有排序前:");

        for (int word:arr){

            System.out.print(word+"\t");

        }

        //先暂定第一个数为最小值,比较n-1轮

        for (int i=0;i<arr.length-1;i++){

            int k=i;//k 是最小的值索引数

            //内部每轮需要比较的n-i次

            for (int j=k+1;j<arr.length;j++){

                if (arr[k]>arr[j]){

                    k=j;//找到最小值的脚标索引值

                }

            }

            //将找到的最小值跟i位值进行互换

            if (i!=k){

                int tmp=arr[i];

                arr[i]=arr[k];

                arr[k]=tmp;

            }

        }

        System.out.println("排序后");

        for (int word:arr){

            System.out.print(word+"\t");

        }

    }






参考:https://blog.csdn.net/u012864854/article/details/79404463

          https://www.jianshu.com/p/27e14bb8539e

          https://blog.csdn.net/shujuelin/article/details/82423852

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

推荐阅读更多精彩内容

  • 总结一下常见的排序算法。 排序分内排序和外排序。内排序:指在排序期间数据对象全部存放在内存的排序。外排序:指在排序...
    jiangliang阅读 1,269评论 0 1
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,101评论 0 52
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好...
    依依玖玥阅读 1,179评论 0 2
  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,076评论 0 2
  • 我们知道人是社会性动物,所以在我们生活中决定我们做事成败的都会归结到交际上。 人与人之间的交谈有闲谈和关键对话两种...
    李摩诘阅读 450评论 0 1