插入排序,希尔排序,选择排序,快速排序,冒泡排序,归并排序

插入排序

1、介绍:
       简单插入排序算法原理:从整个待排序列中选出一个元素插入到已经有序的子序列中去,得到一个有序的、元素加一的子序列,直到整个序列的待插入元素为0,则整个序列全部有序。

  在实际的算法中,我们经常选择序列的第一个元素作为有序序列(因为一个元素肯定是有序的),我们逐渐将后面的元素插入到前面的有序序列中,直到整个序列有序。

2,图解

9 为第一个元素,第一个元素都是有序的。

具体代码:

    /*插入排序*/
    private static int[] InserSort(int[] a){
        int i,j,num=0;
        //下包从第二个值开始,遍历所有值
        for(i=1; i<a.length ; i++){
            //每次排序a[i]与前面的所有值比较
            for(j=0;j<=i;j++){
                if(a[i]<a[j]){
                    //如果小,则插入到数列中,所有数据往后移动
                    int temp = a[i];
                    for(int k=i;k>j;k--){
                        a[k] = a[k-1];
                    }
                    a[j] = temp;
                }
            }
            System.out.println("第"+(++num)+"次排序: "+Arrays.toString(a));
        }
        return a;
    }

希尔排序

1、介绍:

 希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一。本文会以图解的方式详细介绍希尔排序的基本思想及其代码实现。

2,图解

3、代码

    /*希尔排序*/
    private static void shell() {
        int i;        //i为扫描次数
        int j;        //以j来定位比较的元素
        int k=1;      //k打印计数
        int tmp;      //tmp用来暂存数据
        int jmp;      //设定间隔位移量

        jmp=size/2;   //获取增量,且分组
        while (jmp != 0)
        {
            for (i=jmp ;i<size ;i++)
            {
                tmp=data[i]; //组内最后一个值赋值给tmp
                j=i-jmp;
                System.out.println(" j ==>" + j+"\t"+" i ==>" + i +"\t"+"data["+j+"]==>"+data[j]+"\t"+"tmp ==>"+tmp );
                if(tmp < data[j])  //组内排序
                {
                    data[i] = data[j];
                    data[j]=tmp;
                }
                System.out.println(Arrays.toString(data));
            }

            System.out.println("第"+ (k++) +"次增量为【"+jmp+"】排序结果:"+Arrays.toString(data));
            System.out.println("==================================================");
            jmp=jmp/2;    //控制循环数
        }
    }

选择排序

1、简介

 选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

2、图解

1、从左到右顺序比较 
2、第一个元素依次比较第二个元素直到最后一个元素 

(这里需要注意,当第一个元素发生交换时,并不停止比较,而是用替换后的元素,继续比较,这就能在首次找到最小值)
3、第二个元素依次比较第三个元素直到最后一个元素 
4、以此类推

3、代码

    /*选择排序*/
    private static int[] SelectSort(int[] a){
        int temp,num = 0;
        int i ,j;
        for(i=0;i<a.length-1;i++){
            for(j=i+1;j<a.length;j++){
                if(a[i] > a[j]){
                    temp = a[j];
                    a[j] = a[i];
                    a[i]=temp;
                }
            }
            System.out.println("第"+(++num)+"趟排序: "+Arrays.toString(a));
        }
        return a;
    }

快速排序

方法其实很简单:分别从初始序列“6 1 2 7 9 3 4 5 10 8”两端开始“探测”。这里将 6 设置为基准数,先从右往左找一个小于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 2 5 9 3 4 7 10 8

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

6 1 2 5 4 3 9 7 10 8

è¿éåå¾çæè¿°

è¿éåå¾çæè¿°

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

3 1 2 5 4 6 9 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。好了开始动笔吧

       如果你模拟的没有错,调整完毕之后的序列的顺序应该是:

       2 1 3 5 4

       OK,现在3已经归位。接下来需要处理3左边的序列“2 1”和右边的序列“5 4”。对序列“2 1”以2为基准数进行调整,处理完毕之后的序列为“1 2”,到此2已经归位。序列“1”只有一个数,也不需要进行任何处理。至此我们对序列“2 1”已全部处理完毕,得到序列是“1 2”。序列“5 4”的处理也仿照此方法,最后得到的序列如下:

       1 2 3 4 5 6 9 7 10 8

       对于序列“9 7 10 8”也模拟刚才的过程,直到不可拆分出新的子序列为止。最终将会得到这样的序列,如下

       1 2 3 4 5 6 7 8 9 10

       到此,排序完全结束。细心的同学可能已经发现,快速排序的每一轮处理其实就是将这一轮的基准数归位,直到所有的数都归位为止,排序就结束了。下面上个霸气的图来描述下整个算法的处理过程。

è¿éåå¾çæè¿°

2、代码

 private static void quick(int d[], int left, int right) {
        int i, j, tmp;
        int lf_idx;
        int rg_idx;
        //1:第一个键值为d[lf]
        if (left < right) {
            lf_idx = left + 1;
            rg_idx = right;

            //单次循环内排序
            while (true) {
                System.out.print("[处理过程" + (++process) + "]=> " + Arrays.toString(data) + "\n");

                for (j = right; j >= left + 1; j--)   //3:由右向左找出一个键值小于d[lf]者
                {
                    if (d[j] <= d[left]) {
                        rg_idx = j;
                        for (i = left + 1; i <= rg_idx; i++)  //2:由左向右找出一个键值大于d[lf]者
                        {
                            if ((d[i] >= d[left]) || (i == rg_idx)) {
                                lf_idx = i;
                                break;
                            }
                        }
                        break;
                    }
                }

                if (lf_idx < rg_idx)        //4-1:若lf_idx<rg_idx
                {
                    tmp = d[lf_idx];
                    d[lf_idx] = d[rg_idx]; //则d[lf_idx]和d[rg_idx]互换
                    d[rg_idx] = tmp;       //然后继续排序
                } else {
                    break;             //否则跳出排序过程
                }
            }

            //重新设定哨兵,通过递归先将左边排好,再将右边排好
            if (lf_idx == rg_idx)              //5-1:若lf_idx大于等于rg_idx
            {                               //则将d[left]和d[rg_idx]互换
                tmp = d[left];
                d[left] = d[rg_idx];
                d[rg_idx] = tmp;
                //5-2:并以rg_idx为基准点分成左右两半
                quick(d, left, rg_idx - 1); //以递归方式分别为左右两半进行排序
                quick(d, rg_idx + 1, right); //直至完成排序
            }
        }
    }

冒泡排序

1、简介:冒泡排序(Bubble Sort,台湾译为:泡沫排序或气泡排序)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

2、图解

è¿éåå¾çæè¿°

3、代码

   private static int[] BubbleSort(int[] a){

        int temp,num = 0;
        int i , j ;

        for(i = a.length - 1; i > 0; i--){
            for(j = 0 ; j < i; j++) {
                if(a[j] > a[j+1]){
                    temp = a[j];
                    a[j] = a[j+1];
                    a[j+1] = temp;
                }
            }
            System.out.println("第"+(++num)+"趟排序: "+Arrays.toString(a));
        }
        return a;
    }

归并排序

1、简介: 归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

2、图解

3、代码:

private static int[] sort(int[] nums, int low, int high) {
        int mid = (low + high) / 2;
        if (low < high) {
            // 左边
            sort(nums, low, mid);
            // 右边
            sort(nums, mid + 1, high);
            // 左右归并
            merge(nums, low, mid, high);
        }
        return nums;
    }

    private static void merge(int[] nums, int low, int mid, int high) {
        System.out.println("合并的次数"+(++k));
        int[] temp = new int[high - low + 1];
        int i = low;// 左指针
        int j = mid + 1;// 右指针
        int k = 0;

        // 把较小的数先移到新数组中
        while (i <= mid && j <= high) {
            if (nums[i] < nums[j]) {
                temp[k++] = nums[i++];
            } else {
                temp[k++] = nums[j++];
            }
        }

        // 把左边剩余的数移入数组
        while (i <= mid) {
            temp[k++] = nums[i++];
        }

        // 把右边边剩余的数移入数组
        while (j <= high) {
            temp[k++] = nums[j++];
        }

        // 把新数组中的数覆盖nums数组
        for (int k2 = 0; k2 < temp.length; k2++) {
            nums[k2 + low] = temp[k2];
        }
    }
 

猜你喜欢

转载自blog.csdn.net/u012133048/article/details/83096235