zoukankan      html  css  js  c++  java
  • java基础算法--排序大全

      1 package sorting;
      2 
      3 import java.util.*;
      4 //import java.util.Comparator;
      5 //import java.util.PriorityQueue;
      6 //import java.util.Queue;
      7 
      8 public class Sorting {
      9     /************************************序言**********************************************/
     10     /**
     11      * 排序方法:冒泡排序,插入排序,希尔排序,堆排序(2),归并排序(2),快排(2)...
     12      * */
     13     
     14     /**
     15      * 最小值函数
     16      * */
     17     private static <AnyType extends Comparable<? super AnyType>> AnyType min(AnyType a, AnyType b){
     18         if(a.compareTo(b) <= 0)
     19             return a;
     20         else 
     21             return b;
     22     }
     23     
     24     /**
     25      * 交换函数
     26      * */
     27     private static <AnyType extends Comparable<? super AnyType>> void swap(AnyType [] a, int m, int n){
     28         AnyType tmp = a[n];
     29         a[n] = a[m];
     30         a[m] = tmp;        
     31     }
     32     /**********************************BubleSort*****************************************/
     33     /**
     34      * 冒泡排序:BubleSort
     35      * 每次内层循环最大的都被滤到最后
     36      * */
     37     public static <AnyType extends Comparable<? super AnyType>> void bubleSort(AnyType [] a){
     38         for(int i=0;i<a.length;i++){  
     39             for(int j=0;j<a.length-1-i;j++){  
     40                 if(a[j].compareTo(a[j+1]) > 0){   //如果后一个数小于前一个数交换  
     41                     AnyType tmp=a[j];  
     42                     a[j]=a[j+1];  
     43                     a[j+1]=tmp;  
     44                 }  
     45             }  
     46         }             
     47     }
     48     /*************************SelectSort*************************************************/
     49     /***
     50      * 选择排序:SelectSort
     51      * 每次内层循环最小的被滤到最前
     52      */
     53      public static <AnyType extends Comparable<? super AnyType>> void selectSort(AnyType[] a) {
     54             int minIndex;     
     55             for (int i = 0; i < a.length; i++) {
     56                 minIndex = i;                
     57                 for (int j = i + 1; j < a.length; j++) {                   
     58                     if ((a[j].compareTo(a[minIndex])) < 0) {
     59                         minIndex = j;
     60                     }
     61                 }                
     62                 swap(a, i, minIndex);
     63             }
     64         }
     65 
     66     /*************************InsertionSort**********************************************/    
     67     /***
     68      * 插入排序:InsertionSort 
     69      * @param a
     70      * 插入排序的实质是从a[1]~a[a.length-1]开始,逐个比较a[p](p=1,2,...,a.length-1)与a[j-1]的值,直至找到a[p]的位置。
     71      */     
     72     public static <AnyType extends Comparable<? super AnyType>> void insertionSort(AnyType [] a){
     73         int j;
     74         for(int p = 1; p < a.length; p++){
     75             AnyType tmp = a[p]; //务必使用tmp变量,否则可能第一轮比较过后啊a[p]也即a[j]的值被覆盖
     76             for(j = p; j > 0 && tmp.compareTo(a[j - 1])<0;j--){//等于就不挪了,省一次操作
     77                 a[j] = a[j-1];
     78             }
     79             a[j] = tmp;
     80             
     81         }
     82     }
     83     /*************************ShellSort**********************************************/
     84     /**
     85      * 希尔排序:ShellSort 最坏情形:O(N2)
     86      * @param a
     87      * 希尔排序(即间隔排序)的作用:对于间隔k,希尔排序即对k个独立的子数组的一次插入排序
     88      */
     89     public static <AnyType extends Comparable<? super AnyType>> void shellSort(AnyType [] a){
     90         int j;
     91         for(int gap = a.length / 2; gap > 0; gap /= 2 ){
     92             //同时对k个子数组进行间隔排序,相当于和并单独子数组排序的两个for循环 for(int i=0;i<gap;i++){for(int p=i;i<a.length;p+=gap){}}
     93             for(int i = gap;i < a.length;i++){
     94                 //每个子数组的插入排序
     95                 AnyType tmp = a[i];
     96                 for(j = i;j >= gap && tmp.compareTo(a[j-gap])<0;j-=gap){//等于就不挪了,省一次操作
     97                     a[j] = a[j-gap];
     98                 }
     99                 a[j] = tmp;
    100             }
    101         }
    102     }
    103     /*************************HeapSort**********************************************/
    104     /**
    105      * 堆排序:HeapSort1   最坏情形:O(Nlog(N)) 堆排序要比希尔排序要慢
    106      * @param a
    107      * 堆排序使用优先队列java.util.PriorityQueue实现
    108      */        
    109     public static <AnyType extends Comparable<? super AnyType>> void heapSort1(AnyType [] a){
    110         Comparator<AnyType> comparator = new Comparator<AnyType>(){
    111             public int compare(AnyType left, AnyType right){
    112                 return left.compareTo(right) ;
    113              }
    114         };
    115         Queue<AnyType> heap = new PriorityQueue<AnyType>(a.length,comparator);
    116         for(AnyType e:a){
    117             heap.add(e);
    118         }
    119         int i = 0;
    120         while(!heap.isEmpty()){
    121             a[i++] = heap.poll();
    122         }        
    123     }
    124     /****************************************************************************************/
    125     /**
    126      * 堆排序:HeapSort2 最坏情形:O(Nlog(N))
    127      * @param a
    128      * 使用基础代码实现,建堆,排序
    129      */
    130     /**
    131      * 求左子节点
    132      * */
    133     private static int leftChild(int i){
    134         return 2 * i + 1;
    135     }
    136     /**
    137      * 下滤函数:deleteMin(deleteMax)时候使用
    138      * 对于大根堆下滤期间,大数被逐次滤上去(一步一步),小数被一直滤到它该到的位置(for结束后)
    139      * @param a 堆数组
    140      * @param i 开始下滤的起点
    141      * @param n 堆的有效数组长度,随着不断deleteMax操作,堆中元素会不断减少,有效数组长度n也会逐渐减小
    142      */
    143      private static <AnyType extends Comparable<? super AnyType>> void percolateDown(AnyType[] a, int i, int n){
    144          int child;//左右子中较小的那个节点
    145          AnyType tmp = a[i];
    146          
    147          for(; leftChild(i)< n; i = child){//leftChild(i)< n 判断是否到达最后一个叶子节点
    148              child = leftChild(i);
    149              //如果只有一个左子节点,那么不必判断那个更大了
    150              if(child != n-1 && a[child].compareTo( a[child + 1] ) < 0)//child!=n-1为了确定是否有两个子节点
    151                  child++;//将两个儿子中大的那个滤上去
    152              if(tmp.compareTo( a[child]) < 0 ){//等于就不挪了,省一次操作
    153                  a[i]=a[child];//大数被逐次滤上去(一步一步)
    154              }else
    155                  break;
    156          }
    157          a[i]=tmp;//小数被for一直滤下来         
    158      }
    159 
    160     /**
    161      * 排序结果:升序 ,使用大根堆
    162      * 建立大根堆,deleteMin操作,得到排序数组
    163      * 下虑操作:在建立二叉堆和deleteMin中都有使用
    164      * */
    165     public static <AnyType extends Comparable<? super AnyType>> void heapSort2(AnyType [] a){
    166         /*  在无序数组上直接下滤建立大根堆
    167          *  从低向上开始下滤,即最后一个节点的父节点下滤即a[length/2]
    168          *  堆从数组索引0开始,因此左子节点为2*i+1,右子节点为2*i+2  
    169          *  */
    170         for(int i = a.length/2; i >= 0; i--){
    171             percolateDown(a, i, a.length);
    172         }
    173         /*  堆排序:不断deleteMax将堆中最大的元素放置于数组a的末端
    174          *  */
    175         for(int j = a.length-1; j >= 0; j--){
    176             //deleteMax
    177             AnyType tmp = a[j];
    178             a[j] = a[0];
    179             //将队尾元素放置堆根处,开始下滤
    180             a[0] = tmp;
    181             percolateDown(a, 0, j);//初始时刻j为a.length-1
    182         }
    183     }
    184     /*************************MergeSort**********************************************/
    185     /**
    186      * 归并排序:MergeSort1  最坏运行时间O(Nlog(N)) 对空间有要求,线性内存    比较次数最少
    187      * 注意: 归并排序严重依赖于比较元素和数组中移动元素的相对开销,是语言相关的。
    188      *               其中:java中,执行一次泛型排序(Comparator)时 ,比较(不容易内嵌,动态调度)的的开销要大于移动元素(引用赋值);由于比较次数最少,是标准java类库中泛型排序所使用的算法。
    189      *     而 C++则相反,其泛型排序中如果对象庞大,拷贝对象开销大,比较相对省时。C++库中使用快速排序方法。
    190      * @param a
    191      * 实现方式:递归,本质就是一直讲待排序的数组二分下去,直至每一半均只有一个元素然后依次合并,完成排序。
    192      * */
    193     
    194     /**
    195      * 实际完成归并排序的过程的程序
    196      * */
    197     private static <AnyType extends Comparable<? super AnyType>> void merge(AnyType [] a, AnyType [] tmpArray, int leftPos, int rightPos, int rightEnd){
    198         int leftEnd = rightPos - 1;
    199         int tmpPos = leftPos;
    200         int numElements = rightEnd - leftPos + 1;
    201         
    202         while(leftPos <= leftEnd && rightPos <= rightEnd){
    203             if(a[leftPos].compareTo(a[rightPos]) <= 0)//等不等于都得拷贝
    204                 tmpArray[tmpPos++] = a[leftPos++];
    205             else
    206                 tmpArray[tmpPos++] = a[rightPos++];
    207         }        
    208         while(leftPos <= leftEnd){
    209             tmpArray[tmpPos++] = a[leftPos++];
    210         }
    211         while(rightPos <= rightEnd){
    212             tmpArray[tmpPos++] = a[rightPos++];
    213         }
    214         for(int i = numElements; i >0; i--){
    215             a[rightEnd] = tmpArray[rightEnd];
    216             rightEnd--;//注意rightEnd要单独拿出来自减,否则在上个语句中会自减两次
    217         }
    218     }
    219     
    220     /**
    221      * 主递归程序
    222      * */
    223     private static <AnyType extends Comparable<? super AnyType>> void mergeSort(AnyType [] a, AnyType [] tmpArray, int left, int right){
    224         if(left < right){
    225             int center = (left + right)/2;
    226             mergeSort(a, tmpArray, left, center);
    227             mergeSort(a, tmpArray, center + 1, right);
    228             merge(a, tmpArray, left, center + 1, right);//实际完成排序过程
    229         }
    230     }
    231     
    232     /**
    233      * 归并排序驱动程序
    234      * */
    235     public static <AnyType extends Comparable<? super AnyType>> void MergeSort1(AnyType [] a){
    236         AnyType [] tmpArray = (AnyType[]) new Comparable[a.length];
    237         mergeSort(a, tmpArray, 0, a.length - 1);
    238     }    
    239     
    240     /********************************************************************************/
    241     /**
    242      * 归并排序:MergeSort2  最坏运行时间O(Nlog(N))
    243      * @param a
    244      * 实现方式:非递归,从单个元素开始归并合成小组,然后小组之间归并直至归并成一个完整的数组,依旧使用MergeSort1使用的merge函数
    245      * */    
    246     public static <AnyType extends Comparable<? super AnyType>> void MergeSort2(AnyType [] a){
    247         int n = a.length;
    248         AnyType[] tmpArray = (AnyType[]) new Comparable[n]; 
    249         for(int subList = 1; subList < n; subList *=2){
    250             int leftPos = 0;
    251             while(leftPos + subList < n){
    252                 int rightPos = leftPos + subList;
    253 //                int leftEnd = rightPos - 1;
    254                 int rightEnd = min(n-1, rightPos + subList - 1); //一定要注意不能越界 min
    255                 merge(a, tmpArray, leftPos, rightPos, rightEnd);
    256                 leftPos = rightEnd + 1;  //等同于leftPos += 2 * subList;                
    257             }
    258         }
    259     }
    260     /*************************QuickSort**********************************************/
    261     /**
    262      * 快速排序:QuickSort1  平均运行时间:O(NlogN) 最坏运行时间:O(N2)
    263      * 使用三数中值分割法选取枢纽元
    264      * 由于对于小数组(N<=20),快速排序的递归会不如插入排序,因此该程序调用插入排序函数。截止范围CUTOFF=10
    265      * */
    266     
    267     
    268     /**
    269      * 三数中值分割法:取左端,右端,中心位置的三个元素的中值作为枢纽元
    270      * 实在值得注意的一点是:三数中值分割法有效的条件是left+2<=right(即至少要有三个元素)的时候才成立,对于2个及2个一下元素将会出现错误。
    271      * 排序后最小的将位于a[left],最大的位于a[right],枢纽元即中间值a[center]将被放置于a[right-1](亦即交换a[center]与a[right-1])
    272      * 这样在分隔阶段,i,j将从left+1和right-2开始比较
    273      * 三数中值分割法的好处:a[left]比枢纽元小,将作为j的警戒标记;而a[right-1]存放着枢纽元,则自然作为i的警戒标记。
    274      * */
    275     private static <AnyType extends Comparable<? super AnyType>> AnyType median3(AnyType [] a, int left, int right){
    276         int center = (left +  right)/2;
    277         if(a[center].compareTo(a[left]) < 0)
    278             swap(a, center, left);
    279         if(a[right].compareTo(a[left]) < 0)
    280             swap(a, right, left);
    281         if(a[right].compareTo(a[center]) < 0)
    282             swap(a, right, center);
    283         //将枢纽元至于a[right - 1]的位置上
    284         swap(a, center, right - 1);
    285         return a[right - 1];        
    286     }
    287     /**
    288      * 分割策略
    289      * */
    290     private static <AnyType extends Comparable<? super AnyType>> int partition(AnyType [] a, int left, int right){
    291         AnyType pivot = median3(a, left, right);
    292         //由于pivot放置在了a[right - 1]的位置(暂存pivot),因此i,j的取值应该为 left + 1,和right - 2
    293         int i = left, j = right - 1;
    294         for(;;){
    295             //在遇到i,j处值都等于pivot时候停下,但是还得继续道,j<i才算结束,因此while编写要格外注意
    296             while(a[++i].compareTo(pivot) < 0){}//遇到跟pivot枢纽元值相等的值要停下,否则N2效率低下
    297             while(a[--j].compareTo(pivot) > 0){}
    298             if(i < j)
    299                 swap(a, i, j);
    300             else
    301                 break;                
    302         }
    303 //        for(;;){
    304 //            while(a[i].compareTo(pivot) < 0){i++;}
    305 //            while(a[j].compareTo(pivot) > 0){j--;}
    306 //            if(i < j){
    307 //                swap(a, i, j);
    308 //                i++;j--;
    309 //            }
    310 //            else
    311 //                break;                
    312 //        }
    313         swap(a, i, right - 1);
    314         return i;
    315     }
    316     /**
    317      * 快速排序递归程序,主体程序,遇到跟pivot枢纽元值相等的值要停下
    318      * 前提条件:left+1<right(即left+2<=right)
    319      * 实在值得注意的一点是:三数中值分割法有效的条件是left+2<=right(即至少要有三个元素)的时候才成立,对于2个及2个一下元素将会出现错误;
    320      *                 而这里当CUTOFF设置为1时候,仍旧没有错误的原因是else条件下的insertionSort(a)起了作用
    321      * */
    322     private static final int CUTOFF = 10;//CUTOFF>=2
    323     private static <AnyType extends Comparable<? super AnyType>> void qSort(AnyType [] a, int left, int right){
    324         //利用截止范围判断数据量
    325         if(left + CUTOFF <= right){
    326             //获取枢纽元
    327 //            AnyType pivot = median3(a, left, right);
    328 //            //由于pivot放置在了a[right - 1]的位置(暂存pivot),因此i,j的取值应该为 left + 1,和right - 2
    329 //            int i = left, j = right - 1;
    330 //            for(;;){
    331 //                //在遇到i,j处值都等于pivot时候停下,但是还得继续道,j<i才算结束,因此while编写要格外注意
    332 //                while(a[++i].compareTo(pivot) < 0){}//遇到跟pivot枢纽元值相等的值要停下,否则N2效率低下
    333 //                while(a[--j].compareTo(pivot) > 0){}
    334 //                if(i < j)
    335 //                    swap(a, i, j);
    336 //                else
    337 //                    break;                
    338 //            }
    339 //            for(;;){
    340 //                while(a[i].compareTo(pivot) < 0){i++;}
    341 //                while(a[j].compareTo(pivot) > 0){j--;}
    342 //                if(i < j){
    343 //                    swap(a, i, j);
    344 //                    i++;j--;
    345 //                }
    346 //                else
    347 //                    break;                
    348 //            }
    349             //因为i左边都比pivot小,i及i右边除了right-1除存放着pivot外都比pivot大,因此将i处值与right-1处值交换
    350             //即得到i左边都比其小,右边都比其大,i即pivot排序好的正确位置(换回pivot)
    351 //            swap(a, i, right - 1);
    352             int i = partition(a, left, right);
    353             //i已排好序
    354             qSort(a, left, i - 1);
    355             qSort(a, i + 1, right);
    356         }else{
    357             insertionSort(a);//在这里处理了当CUTOFF等于1时的情景不会出错。当CUTOFF等于0时首先是不允许的(那样left就等于right了),其次这会导致median3()函数数组索引越界异常
    358             }
    359     }
    360     /**
    361      * 快速排序驱动程序
    362      * */
    363     public static <AnyType extends Comparable<? super AnyType>> void quickSort(AnyType [] a){
    364         qSort(a, 0, a.length - 1);
    365     }
    366     
    367     /*********************************QuickSort2***************************************/
    368     /**
    369      * 分割策略
    370      * */
    371     private static <AnyType extends Comparable<? super AnyType>> int partition2(AnyType [] a, int start, int end){
    372         int i = start, j = end;
    373         AnyType base = a[start];            
    374         while(i < j ){
    375             while((a[j].compareTo(base) > 0) && (j > i))
    376                 j--;
    377             if(i < j){
    378                 a[i] = a[j];
    379                 i++;//
    380             }
    381             while((a[i].compareTo(base) < 0) && (i < j))
    382                 i++;
    383             if(i < j){
    384                 a[j] = a[i];
    385                 j--;//
    386             }            
    387                     
    388         }//while
    389         a[i] = base;
    390         return i;
    391     }
    392     /**
    393      * 使用数组第一位作为枢纽元
    394      * 前提条件:start<end
    395      * */
    396     private static <AnyType extends Comparable<? super AnyType>> void qSort2(AnyType [] a, int start, int end){
    397         if(start < end){
    398 //            int i = start, j = end;
    399 //            AnyType base = a[start];            
    400 //            while(i < j ){
    401 //                while((a[j].compareTo(base) > 0) && (j > i))
    402 //                    j--;
    403 //                if(i < j){
    404 //                    a[i] = a[j];
    405 //                    i++;//
    406 //                }
    407 //                while((a[i].compareTo(base) < 0) && (i < j))
    408 //                    i++;
    409 //                if(i < j){
    410 //                    a[j] = a[i];
    411 //                    j--;//
    412 //                }            
    413 //                        
    414 //            }//while
    415 //            a[i] = base;
    416             int i = partition2(a, start, end);
    417             
    418             qSort2(a, start, i-1);
    419             qSort2(a, i+1, end);
    420         }
    421         
    422     }
    423     /**
    424      * 驱动程序
    425      * 使用数组第一位作为枢纽元
    426      * */
    427     public static <AnyType extends Comparable<? super AnyType>> void quickSort2(AnyType [] a){
    428         qSort2(a, 0, a.length-1);
    429     }
    430     /*********************************QuickSort3***************************************/
    431     /**
    432      * 三数中值分割的使用非递归的快速排序
    433      * */
    434     public static <AnyType extends Comparable<? super AnyType>> void quickSort3(AnyType [] a){
    435          if(a==null||a.length<=0)return;  
    436             Stack<Integer> index=new Stack<Integer>();  
    437             int start=0;  
    438             int end=a.length-1;  
    439               
    440             int pivotPos;  
    441                   
    442             index.push(start);  
    443             index.push(end);  
    444                   
    445             while(!index.isEmpty()){  
    446                 end=index.pop();  
    447                 start=index.pop();  
    448                 if(start+1<end){//三数中值必备
    449                     pivotPos=partition(a,start,end); 
    450                     
    451                     if(start<pivotPos-1){  
    452                         index.push(start);  
    453                         index.push(pivotPos-1);  
    454                     }  
    455                     if(end>pivotPos+1){  
    456                         index.push(pivotPos+1);  
    457                         index.push(end);  
    458                      
    459                     }
    460                 }else{//三数中值必备
    461                     if(a[start].compareTo(a[end])>0)
    462                         swap(a, start, end);
    463                 }
    464             }     
    465     }
    466     /*********************************QuickSort4***************************************/
    467     /**
    468      * 使用第一值为枢纽元的使用非递归的快速排序
    469      * */
    470     public static <AnyType extends Comparable<? super AnyType>> void quickSort4(AnyType [] a){
    471          if(a==null||a.length<=0)return;  
    472             Stack<Integer> index=new Stack<Integer>();  
    473             int start=0;  
    474             int end=a.length-1;  
    475               
    476             int pivotPos;  
    477                   
    478             index.push(start);  
    479             index.push(end);  
    480                   
    481             while(!index.isEmpty()){  
    482                 end=index.pop();  
    483                 start=index.pop();  
    484 //                if(start<end){  //可有可无,因为压栈的时候已能确定start<end,此处判断是恒成立的
    485                     pivotPos=partition2(a,start,end); 
    486                     
    487                     if(start<pivotPos-1){  
    488                         index.push(start);  
    489                         index.push(pivotPos-1);  
    490                     }  
    491                     if(end>pivotPos+1){  
    492                         index.push(pivotPos+1);  
    493                         index.push(end);  
    494                      
    495                     }
    496 //                }
    497             }     
    498     }
    499 
    500     /*-----------------------------------------main-------------------------------------------------*/
    501     public static void main(String[] args) {
    502         // TODO Auto-generated method stub
    503         /**
    504          * Test case: Sort the array.
    505          * */        
    506 //        Integer[] a ={3,1,4,1,5,9,111,2,6,142,543,123,65,453,123,879,572,434,111,242,811,102};
    507         Integer[] a ={3,1,4,1,5,9,2,6};
    508         System.out.println("Before sorting:");
    509         for(Integer i:a){
    510             System.out.print(i+",");
    511         }
    512         System.out.println();
    513         
    514         Sorting.quickSort4(a);//排序方法调用
    515         System.out.println("After sorting:");
    516         for(Integer i:a){
    517             System.out.print(i+",");
    518         }
    519         System.out.println();
    520 
    521         
    522     }
    523 
    524 }
  • 相关阅读:
    js/jquery键盘事件及keycode大全
    阿里巴巴首款商用字体免费开放:阿里巴巴普惠字体
    从kinit到kerberos安全机制
    react中dangerouslySetInnerHTML使用
    URLSearchParams
    React router的Route中component和render属性的使用
    SSH 命令的三种代理功能(-L/-R/-D)
    H5 直播的疯狂点赞动画是如何实现的?(附完整源码)
    CenterOS中安装Redis及开机启动设置
    使用require.context实现前端自动化
  • 原文地址:https://www.cnblogs.com/LolaLiu/p/4198693.html
Copyright © 2011-2022 走看看