Java常用排序算法/程序员必须掌握的8大排序算法

分类:

1)插入排序(直接插入排序、希尔排序)

2)交换排序(冒泡排序、快速排序)

3)选择排序(直接选择排序、堆排序)

4)归并排序

5)分配排序(基数排序)

所需辅助空间最多:归并排序

所需辅助空间最少:堆排序

平均速度最快:快速排序

不稳定:快速排序,希尔排序,堆排序。

先来看看8种排序之间的关系:

 

1、插入排序

 基本思想:

在要排序的一组数中,假设前面(n-1)[n>=2] 个数已经是排好顺序的,

        现在要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的。

        如此反复循环,直到全部排好顺序。

        

JAVA实现:

/**

          * 插入排序

          * 排序原理:

          * 当数组长度为1时,直接返回数组,当数组长度大于1时, 每次取数组中的一

          * 个数跟第一个数进行比较,如果大于它就插在右边,

          * 小于它就插在左边,就跟打扑克一样,它前面的数组等于是已经排序了的。

          * @param arrays

          * @param len

          * @return

          */

         public static int[] chaRuSort(int[] arrays,int len) {

                 int middle = 0;

                 if (len == 0 || len == 1)

                          return arrays;

                 for (int i = 1; i < len;i++) {// 从第二个数据开始插入

                          if (arrays[i] <arrays[i - 1]) {// 如果需要排序的数字比前面的最大数据要小,则表示它需要放到前面去

                                   middle =arrays[i];// 存储需要插入的数组

                                   for (int j =i - 1; j >= 0; j--) {// 从右边开始比较,当它比某个数大时,则表示他需要插入这个位置,同时每次循环的数字都往后挪一位

                                            if(arrays[j] < middle) {

                                                    arrays[j+ 1] = middle;

                                                    break;//以插入就可以跳出循环

                                            }

                                            arrays[j+ 1] = arrays[j];

                                            if(j == 0)

                                                    arrays[0]= middle;// 但如果它一直没有跳出循环,则直接把它插入第一个位置,但必须要在第一个数字已换位置之后

                                   }

                          }

                 }

                 return arrays;

         }

 

 2、希尔排序

基本思想:

算法先将要排序的一组数按某个增量d(n/2,n为要排序数的个数)分成若干组,

每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小

的增量(d/2)对它进行分组,在每组中再进行直接插入排序。当增量减到1时,进行直接插入排序后,排序完成。

JAVA实现:

       /**

          * 希尔排序 排序原理:

          * 先把数组分为part份,

          * 之后对每份都进行插入排序

          * @param arrays

          * @param len

          * @param part,分多少份

          * @return

          */

         public static int[] xiErSort(int[]arrays, int len, int part) {

                 for (int h = len / part; h >0; h /= part) {

                          for (int i = h; i <len; i++) {

                                   for (int j =i - h; j >= 0; j -= h) {

                                            if(arrays[j] > arrays[j + h]) {

                                                    inttemp = arrays[j];

                                                    arrays[j]= arrays[j + h];

                                                    arrays[j+ h] = temp;

                                            }

                                   }

                          }

                 }

                 return arrays;

         }

3、选择排序

基本思想

在要排序的一组数中,选出最小的一个数与第一个位置的数交换;

然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。

JAVA实现:

/**

          * 直接选择排序

          * 排序原理:

          * 第一次从R[0]~R[n-1]中选取最小值,与R[0]交换,

          *  第二次从R[1]~R[n-1]中选取最小值,与R[1]交换,

          * …., 第i次从R[i-1]~R[n-1]中选取最小值,

          * 与R[i-1]交换, …..,

          * 第n-1次从R[n-2]~R[n-1]中选取最小值,与R[n-2]交换,

          * 共通过n-1次,得到一个从小到大排列的有序序列。

          * @param arrays

          * @param len

          * @return

          */

         public static int[] xuanZeSort(int[]arrays, int len) {

                 int middle = 0, minIndex = 0;

                 for (int i = 0; i < len;i++) {

                          minIndex = i;

                          for (int j = i + 1; j< len; j++) {// 从i+1开始比较,如果比需要比较的arrays[middle]小,前面已经排序,当找到比它小的,其余的数就跟这个更小的比较,直到找到最小值。

                                   if(arrays[minIndex] > arrays[j])

                                            minIndex= j;// 把比较索引只想更小的那个数的索引。

                          }

                          if (i != minIndex) {//如果最小值下标进行了改变,则说明数组有比前面最大值更小的值,需要还位置。

                                   middle =arrays[i];

                                   arrays[i] =arrays[minIndex];

                                   arrays[minIndex]= middle;

                          }

                 }

                 return arrays;

         }

 4、堆排序

基本思想:

堆排序是一种树形选择排序,是对直接选择排序的有效改进。堆的定义如下:具有n个元素的序列(h1,h2,…,hn),当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1)(i=1,2,…,n/2)时称之为堆。在这里只讨论满足前者条件的堆。由堆的定义可以看出,堆顶元素(即第一个元素)必为最大项(大顶堆)。

完全二叉树可以很直观地表示堆的结构。堆顶为根,其它为左子树、右子树。初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个堆,这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。

交换,从堆中踢出最大数

剩余结点再建堆,再交换踢出最大数

依次类推:最后堆中剩余的最后两个结点交换,踢出一个,排序完成。

JAVA实现:

publicvoid heapSort(int[] a){ 

        System.out.println("开始排序");

        int arrayLength=a.length; 

        //循环建堆

        for(int i=0;i<arrayLength-1;i++){

            //建堆

            buildMaxHeap(a,arrayLength-1-i);

            //交换堆顶和最后一个元素

            swap(a,0,arrayLength-1-i);

           System.out.println(Arrays.toString(a));

        }

    }

  

   

  

    private void swap(int[] data, int i, int j){ 

        // TODO Auto-generated method stub 

        int tmp=data[i]; 

        data[i]=data[j];

        data[j]=tmp;

    }

  

    //对data数组从0到lastIndex建大顶堆

    private void buildMaxHeap(int[] data, intlastIndex) { 

        // TODO Auto-generated method stub 

        //从lastIndex处节点(最后一个节点)的父节点开始

  

        for(int i=(lastIndex-1)/2;i>=0;i--){

            //k保存正在判断的节点

            int k=i; 

            //如果当前k节点的子节点存在

            while(k*2+1<=lastIndex){

                //k节点的左子节点的索引

                int biggerIndex=2*k+1;

               //如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在

                if(biggerIndex<lastIndex){

                    //若果右子节点的值较大

                   if(data[biggerIndex]<data[biggerIndex+1]){

                        //biggerIndex总是记录较大子节点的索引

                        biggerIndex++;

                    }

                }

  

                //如果k节点的值小于其较大的子节点的值

              if(data[k]<data[biggerIndex]){

                    //交换他们

                    swap(data,k,biggerIndex);

                    //将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值

                    k=biggerIndex;

                }else{

                    break;

                }

            }

        }

    }

        

5、冒泡排序

基本思想:

在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。

JAVA实现

/**

          * 冒泡排序

          * 排序原理:从待排序序列的起始位置开始,从前往后依次比较各个位置和其后一位置的大小并执行。

          * 如果当前位置的值大于其后一位置的值,就把他俩的值交换(完成一次全序列比较后,序列最后位

          * 置的值即此序列最大值,所以其不需要再参与冒泡)。将序列的最后位置从待排序序列中移除。

          * 若移除后的待排序序列不为空则继续执行,否则冒泡结束。

          * @param arrays,将排序的数组

          * @param len,数组长度

          * @return,排序后的数组

          */

         private static int[] maoPaoSort(int[]arrays, int len) {

                 int middle = 0;

                 for (int i = 0; i < len - 1;i++) {

                          for (int j = 0; j <len - i - 1; j++) {

                                   if (arrays[i]> arrays[j]) {// 把前一个比较数据大于后面一个数据的放到后面,从小到大排序

                                            middle= arrays[i];

                                            arrays[i]= arrays[j];

                                            arrays[j]= middle;

                                   }

                          }

                 }

                 return arrays;

         }

 

         /**

          * 冒泡排序优化:

          * 排序原理:

          * 当数据位置不在互换时,则表示前面的数据都大于后面的数据,排序已完成

          * @param arrays,将排序的数组

          * @param len,数组长度

          * @return,排序后的数组

          */

         public static int[]maoPaoYouHuaSort(int[] arrays, int len) {

                 int middle = 0;

                 boolean flag = true;

                 while (flag) {

                          flag = false;// 如果没有交换,则flag=false,则跳出循环

                          for (int i = 0; i <len - 1; i++) {

                                   if (arrays[i]> arrays[i + 1]) {// 把前一个比较数据大于后面一个数据的放到后面,从小到大排序

                                            middle= arrays[i];

                                            arrays[i]= arrays[i + 1];

                                            arrays[i+ 1] = middle;

                                            flag= true;

                                   }

                          }

                          len--;// 去除最后一个排序正确的

                 }

                 return arrays;

         }

 6、快速排序

基本思想:

选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。

JAVA实现:

/**

         *快速排序:

         *排序原理:

         *把一个需要排序的数组分成2份, 之后取数组的left值进行比较,在左边找到比数组下

         *标left大的就换位置,在右边找到比数组下标left 小的就换位置,直到数组有一个值的左边都比它小,右

         *边都比它大,也就是i和j相等的时候就完成第一次排序, 之后递归对它左右2边的数组进行排序,直到数组不再出

         *现i<j,也就是数组只有一个元素才结束。

         *@param arrays,将排序的数组

         *@param left,数组的左边起始位置,0

         *@param right,数组的右边起始位置,arrays.length-1

         *@return,排序后的数组

         */

        private static int[] kuaiSuSort(int[]arrays, int left, int right) {

               int i = left, j = right, key =arrays[left];

               while (i < j) {// 只有当i=j时,才完成第一次排序,

                       while (i < j&& arrays[j] >= key)

                               // 循环查询,从右边开始比较,比key大就就说明这个值本身就应该放在右边,不用换位置,之后继续往前查询,但查到右边第二个值比左边的小时,跳出循环。

                               j--;

                       if (i < j) {// 跳出了循环,如果i还是大于j,则表示查询到的小于或等于key的数字在key的右边,需要互换位置,把arrays[i]的值与arrays[j]互换。

                               arrays[i] =arrays[j];// arrays[i]的值已经保存在了key里面,只是这里没有赋值,到后面赋值。

                               i++;

                       }

                       while (i < j&& arrays[i] <= key)

                               // 循环查询,从左边开始比较,比key小就就说明这个值本身就应该放在左边,不用换位置,之后继续往前查询,但查到某个值比不小于key,跳出循环。

                               i++;

                       if (i < j) {// 跳出了循环,如果i还是大于j,则表示查询到的小于或等于key的数字在key的左边,需要互换位置,把arrays[i]的值与arrays[j]互换

                               arrays[j] =arrays[i];// arrays[j]的值已经保存在了arrays[i]里面,只是这里没有赋值,到后面赋值。

                               j--;

                       }

                       arrays[i] = key;

                       kuaiSuSort(arrays, left,i - 1);

                       kuaiSuSort(arrays, j + 1,right);

               }

               return arrays;

        }

 7、归并排序

基本排序:

归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

JAVA实现:

/**

         *归并排序 排序原理:把排序数组分成2份,

         *新建一个临时数组,存放排序后的数组,且这两个数组已经排序了的,之后比较这两个数组的初始值,小的放入临时数组

         *,之后把它和临时数组的索引+1,最后把还有数据的数组数字直接放在最后

         *,前提条件,(两个数组已经排序),但在数组中都只有一个数字的时候才能说数组已经进行了排序。

         *@param arrays

         *@param ones,第一个数组的起始位置

         *@param twos,第二个数组的起始位置,twos-1也即第一个数组的终止位置。

         *@param twot,第二个数组的终止位置

         *@return

         */

        public static int[] guiBinSort(int[]arrays, int ones, int twos, int twot) {

               int[] tem = newint[arrays.length];

               int i = ones, j = twos, k = 0;

               while (i < twos && j<= twot) {// 当i,j还在数组里面,则表示2个数组都还有值,否则就有一个数组里面已经没有数字

                       if (arrays[i] <=arrays[j]) {// 当arrays[i]小一些,就把它放入临时数组,临时数组和第一个数组的下标加1

                               tem[k] =arrays[i];

                               i++;

                       } else {

                               tem[k] =arrays[j];

                               j++;

                       }

                       k++;

               }

               while (i < twos) {// 表示第一个数组里面还有数字

                       tem[k] = arrays[i];

                       i++;

                       k++;

               }

               while (j <= twot) {// 表示第一个数组里面还有数字

                       tem[k] = arrays[j];

                       j++;

                       k++;

               }

               for (int g = 0; g < k; g++) {//把已排序的内容重新替换排序的数据

                       arrays[g] = tem[g];

               }

               return arrays;

        }

 

        /**

         *只有单个元素时,数组才能说时有序的

         *

         *@param arrays

         *@param len

         *@return

         */

        public static int[] guiBinSort(int[]arrays, int len) {

               for (int i = 1; i < len; i++){

                       guiBinSort(arrays, 0, i,i);// 归并排序arrays[0-0]和arrays[1-1],这个就排序了

               }

               /*

                * int i=1; while(i<len){

                * guiBinSort(arrays,0,i,i);//归并排序arrays[0-0]和arrays[1-1],这个就排序了

                * i++;//递加1就变成了归并归并排序arrays[0-1]和arrays[2-2],一直递归 }

                */

               return arrays;

        }

8、基数排序

基本思想:

将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

JAVA实现

/**

         *基数排序

         *实现原理:将所有待比较数值(正整数)统一为同样的数位长度,

         *数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。

         *这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

         *@param arrays

         *@param d,最大有几位数

         *@return

         */

        public static int[] jiShuSort(int[]arrays, int d) {

               int k = 0;

               int n = 1;

               int m = 1; // 控制键值排序依据在哪一位

               int[][] temp = newint[10][arrays.length]; // 数组的第一维表示可能的余数0-9

               int[] order = new int[10]; // 数组orderp[i]用来表示该位是i的数的个数

               while (m <= d) {

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

                               int lsd =((arrays[i] / n) % 10);

                               temp[lsd][order[lsd]]= arrays[i];

                               order[lsd]++;

                       }

                       for (int i = 0; i <10; i++) {

                               if (order[i] !=0)

                                      for (int j= 0; j < order[i]; j++) {

                                              arrays[k] = temp[i][j];

                                              k++;

                                      }

                               order[i] = 0;

                       }

                       n *= 10;

                       k = 0;

                       m++;

               }

               return arrays;

        }

 

        /**

         *变种的基数排序,

         *把排序数组中的所有数字分成d份 必须都是正数,

         *每个数在什么位置就放入那个数组中,

         *之后对每个数组进行排序,在合并

         *@param arrays

         *@param len

         *@param d,最大数据有多少位

         *@return

         */

        public static int[] jiShuSort(int[]arrays, int len, int d) {

               int n = 0;// 临时存储arrays[i]的值

               int tem = 0;// 临时存储位数值

               int k = 0; // 从新排序索引

               int min = 0, max = 0;// 临时存储最大值和最小值

               int[][] temp = new int[d][len];// 数组的第一维表示可能的余数0-9

               for (int j = d; j >= 0; j--) {

                       for (int i = 0; i <len; i++) { // 把数值分配到指定的类中

                               n = arrays[i];

                               min = (int) Math.pow(10,j - 1);

                               max = (int)Math.pow(10, j);

                               if (min <= n&& n < max)

                                      temp[j -1][i] = n;

                       }

               }

               for (int i = 0; i < d; i++) {

                       temp[i] =guiBinSort(temp[i], len);// 每一个数组再次进行排序

                       for (int j = 0; j <len; j++) {// 之后把排序之后的每个数组重新放入数组中

                              if(temp[i][j] != 0) {

                                      arrays[k]= temp[i][j];

                                      k++;

                               }

                       }

               }

               return arrays;

        }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值