排序算法,按照自己的理解描述的



1> 插入排序:

 基本思想: 把需要排序的集合分为两部分,一部分是排序好的,一部分未排序的。就像打扑克一样,如果你习惯从左到右按从小到达的方式排列,开始都背面盖着放在桌上,然后抓起一张,抓第二张时,先和手上的第一张对比,如果点数大于第一张,那就把它插到第一张的右边。剩下桌上的牌都按照这个方式去处理。

 实际上,在用java数组处理的时候,还是和玩扑克是有区别的。扑克的左右没有边界限制,而实际数组有边界限制,所以,需要考虑到边界的问题,所以最好是从右到左查找过去,不会产生越界的问题。

 

 

------------------用java数组进行实现------------------------

从右到左查找

---------------------------code-begin-----------------------

public static int[] insertSort(int[] rawArr) {

       

       // 常识性的判断,不要没有牌或者牌只有1张

       if (rawArr == null || rawArr.length < 2) {

           return rawArr;

       }


       //从第二个数开始,第一张已经抓在手上了

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

            int j = i - 1 ; //对比手上的牌,最右边的那张

            int insertVal = rawArr[i] ; //待插入的牌


            while(j > -1 && rawArr[j] > insertVal) { //如果牌比待插入的大,往左边继续看

                 rawArr[j+1] = rawArr[j]; //把牌向右挪一位

                 j-- ; //检查左边的牌

            }


            rawArr[j+1] = insertVal ; //最后,把牌插入正确的位置

            

            //到下一个循环,也就是下一张没上来的牌。

           

       }

               

               return rawArr ;


   }

----------------------------code-end------------------------


2> 冒泡排序:

基本思想:

  可以想想成数组的样子是从上到下的。如果排序是从大到小,那么就是从底部开始两两对比,哪个数大就放到上面。这样经过第一轮的对比,最大的数就会“浮”到最上面,也就是第一个位置。第二轮的时候,最上面的数就不用对比了,第二轮完毕之后,倒数第二大的数就会“浮”到倒数第二个位置。依次类推,最后循环完,就会按从大到小的顺序排列了。


-------------------------code-begin-------------------------

   public int[] popUpSort(int[] rawArr) {

       if(rawArr == null || rawArr.length < 2) {

           return rawArr ;

       }


        //有n个数,就是运行n-1次,最后一个数就不用比对了

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

           //两个两个对比,从下往上,到排序完的那个数为止(不包含)

           for(int j = 0 ; j < rawArr.length - i ; j ++) {

               if(rawArr[j] < rawArr[j+1]) {

                   int tmp = rawArr[j];

                   rawArr[j] = rawArr[j+1];

                   rawArr[j+1] = tmp ;

               }

           }


       }


       return rawArr ;


   }

-------------------------code-end---------------------------


3> 归并排序

基本思想:

  一个无序的数组,假如要从小到大进行排序。先分割成两部分,然后每部分再进行分割,直到分割的部分只有一个元素时,就认为它是有序的。这时候,再进行合并,合并的流程就是新建一个临时数组,长度是两个子数组长度的和。然后分别扫描两个子数组(a和b),如果a[0]小于b[0],那就把a[0]先加到临时数组中(反之,就是把b[0]先加到临时数组中),然后a数组向前移动一位,然后a[1]再与b[0]比较,比较小的就加到临时数组中。以此类推,当有一个数组添加完毕之后,而另一个数组有所剩余,就把剩下的元素都加到临时数组中,这样就完成了排序。然后递归的返回,然后合并,最终就得到整个数组的排序后的数组。

  

-------------------------code-begin-------------------------

   public int[] mergeSort(int[] rawArr) {

       if(rawArr == null && rawArr.length < 2) {

           return rawArr;

       }


       return merge(rawArr);


   }


   private int[] merge(int[] slice) {

      

       //只有一个元素,直接就是排序好的

       if(slice.length == 1) {

           return slice;

       }

   

       //切成两部分

       int half = slice.length / 2 ;

       int[] aArr = getSubArrayOf(slice,0,half);

       int[] bArr = getSubArrayOf(slice,half,slice.length);

       

       //递归调用,这样aArr和bArr就是排序好的了

       aArr = merge(aArr) ;

       bArr = merge(bArr) ;

       

       //下面就进行合并

       

       int aLength = aArr.length ;

       int bLength = bArr.length ;

       int totalLength = aLength + bLength ;

       

       int[] mArr = new int[totalLength];

       int i = 0 ;

       int j = 0 ;

       int k = 0 ;

     

       //扫描两个子数组,根据条件进行排序

       while(i < aLength && j < bLength) {

           if(aArr[i] < bArr[j]) {

               mArr[k++] = aArr[i++];

           }else {

               mArr[k++] = bArr[j++] ;

           }

       }

       

       //如果是a数组剩余,就把剩下的加到父数组中

       while(i < aLength) {

           mArr[k++] = aArr[i++];

       }


       //如果是b数组剩余,就把剩下的加到父数组中

       while( j < bLength) {

           mArr[k++] = bArr[j++];

       }

       

        //合并好就返回

        return mArr;

   }

   

   private int[] getSubArrayOf(int[] arr, int startIndex , int endIndex) {

       

       if(endIndex < startIndex) {

           return null;

       }

        int len = endIndex - startIndex ;

       int[] newArr = new int[len];


       for(int i = startIndex ; i < endIndex ; i++) {

           newArr[i-startIndex] = arr[i];

       }



       return newArr;


   }

-------------------------code-end---------------------------  

  



4> 堆排序

堆是树状结构的,主要有两个特点:

1) 根节点的值最小(最大)

2)子树也是一个堆,称为最小堆(最大堆)

  

二叉堆是完全二叉树或者是近似完全二叉树来构造的堆。

还有其他“堆”(二项式堆,斐波纳契堆)



利用堆的结构,比如最小堆,那么根节点是当前的树状结构中值最小的元素。

那么,如果一组数要从小到大,先把它调节成一个最小堆,然后每次取它的根节点,然后删除根节点,再对剩下的树状结构进行调整,重新成为一个最小堆。然后再取根节点,这样循环的做下去,这样,最后元素都取完了,那么也就把数据都从小到大排序好了。

这样,需要两个步骤对排序进行辅助。

1)根节点删除

2)调整成堆


按照数组的方式存储堆,那么节点之间的关系为:

节点位置为i。那么父节点位置为 i-1 / 2

两个子节点的位置为 2*i + 1 与 2*i + 2


如果是一个数组,要使用堆的性质进行排序。那么就是:

1)调整成堆

2)把根节点a[0]和最后一个节点a[n-1]对调。

然后再对a[0]到a[n-2]进行恢复堆,然后再把a[0]和a[n-2]进行对调。

循环下去,直到a[0],这样就排好了。




5> 快速排序

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

http://www.cnblogs.com/surgewong/p/3381438.html

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

快速排序的基本思想: 通过一次循环,把需要排序的元素分割成两部分A和B,长度不一定相等,但其中A中任何元素的值比B中任何元素的值都要小。

然后再递归调用,分别再对A和B进行切割,分别分成两部分,也是一部分中的元素值比另一部分都小。循环分割,到只有一个数,那么每段都是排序好了。

然后再递归返回,由于每一段都是已经排序好的,那么返回的时候,两段就不需要重新进行比较,直接连接起来就是排序好的。

那么,具体怎么在一次循环中就把数据分割成满足要求的两部分呢?

先选一个值x,然后分别从数组的两端进行扫描,比这个数小的就放到这个数的左边,比这个数大的就放到这个数的右边。


以下为例:


  0     1     2     3     4     5     6     7    

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

| 46 | 30 | 82 | 90 | 56 | 17 | 95 | 15 |

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

 i=0                                          j=7

 


选第一个数 46 为x , 然后开始比较, a[j] = 15 < 46 ,那么就交换两个数的位置,同时i向前移动一位。



  0     1     2     3     4     5     6     7    

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

| 15 | 30 | 82 | 90 | 56 | 17 | 95 | 46 |

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

       i=1                                    j=7



然后再比较, a[i] = 30 < 46 ,那么不动,i再移动一位


  0     1     2     3     4     5     6     7    

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

| 15 | 30 | 82 | 90 | 56 | 17 | 95 | 46 |

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

               i=2                           j=7

           

然后再比较,a[i] = 82 > 46 ,那么交换两者的位置,然后j向后移动一位。


  0     1     2     3     4     5     6     7    

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

| 15 | 30 | 46 | 90 | 56 | 17 | 95 | 82 |

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

           i=2                 j=6


然后比较  a[j] = 82 > 46 , 不动,j再向后移动一位


  0     1     2     3     4     5     6     7    

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

| 15 | 30 | 46 | 90 | 56 | 17 | 95 | 82 |

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

               i=2              j=5


然后再比较, a[j] = 17 < 46 ,两者交换,i向前移动一位


  0     1     2     3     4     5     6     7    

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

| 15 | 30 | 17 | 90 | 56 | 46 | 95 | 82 |

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

                      i=3        j=5

                

再比较 a[i] = 90 > 46 ,两者交换,j向后移动一位



  0     1     2     3     4     5     6     7    

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

| 15 | 30 | 17 | 46 | 56 | 90 | 95 | 82 |

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

                     i=3  j=4


再比较 a[j] = 56 > 46 ,不交换,j向后移动一位


  0     1     2     3     4     5     6     7    

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

| 15 | 30 | 17 | 46 | 56 | 90 | 95 | 82 |

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

              i=j=3

      

      

此时发现i=j=3,这时候,此次分割结束。


这样,数组被分割成[0-2][3][4-7]三个区间,然后再递归的对[0-2]和[4-7]按照以上方式进行分割。

最后分割成一个个数之后再分别合并起来,组成一个有序的序列。


-------------------------code-begin-------------------------

   private void quick_sort(int[] rawArr,int left , int right) {

       

       if(left < right) {

       

           int i = left ;

       

           int j = right ;

       

           int x = rawArr[i];

           

           while( i < j ) {


               while(i < j && rawArr[j] < x) {

                   j-- ;

               }


               if(i < j) {

                   rawArr[i++] = rawArr[j] ;

               }


               while(i < j && rawArr[i] >= x) {

                   i++ ;

               }


               if(i < j) {

               

                   rawArr[j--] = rawArr[i];

               }


           }


           rawArr[i] = x;


           quick_sort(rawArr,left,i-1);

           quick_sort(rawArr,i+1,right);

       }

-------------------------code-end---------------------------


6> shell排序


通过不断“对折”,然后对各个分组进行“插入排序”。

例如以下数据:


有8个数,第一次先取 gap = 4


  0     1     2     3     4     5     6     7    

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

| 46 | 30 | 82 | 90 | 56 | 17 | 95 | 15 |

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


这样数据就分为了(0,4)(1,5)(2,6)(3,7)总共4组。 然后对每组元素分别进行“插入排序”。


  0     1     2     3     4     5     6     7    

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

| 46 | 17 | 82 | 15 | 56 | 30 | 95 | 90 |

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


然后再“对折”,gap = gap / 2 = 2。这样分为了2组。

(0,2,4,6)(1,3,5,7) ,然后再对每组进行“插入排序”。


  0     1     2     3     4     5     6     7    

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

| 46 | 15 | 56 | 17 | 82 | 30 | 95 | 90 |

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


然后再“对折”,gap= gap / 2 = 1 这样就只有1组。(0,1,2,3,4,5,6,7) 再进行插入排序。


  0     1     2     3     4     5     6     7    

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

| 15 | 17 | 30 | 46 | 56 | 82 | 90 | 95 |

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


然后再对折  gap = gap / 2 = 0 结束。



-------------------------code-begin-------------------------

       for(gap = n / 2 ; gap > 0 ; gap /= 2) { // count of split


           for(int i = 0 ; i < gap ; i++) { // group size


               for(int j = i + gap ; j < n ; j += gap) {


                   if(rawArr[j] < rawArr[ j- gap ]) {


                       int insertVal = rawArr[j] ;


                       int k = j - gap ;


                       while(k >= 0 && rawArr[k] > insertVal) {


                           rawArr[k + gap] = rawArr[k] ;


                           k -= gap ;


                       }


                          rawArr[k + gap] = insertVal ;


                   }


               }


           }


       }


-------------------------code-end---------------------------


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值