九种基本排序算法总结

排序分类: 1、插入排序:直接插入排序,二分法插入排序,希尔排序; 2、选择排序:简单选择排序,堆排序; 3、交换排序:冒泡排序,快速排序; 4、归并排序;

5、基数排序;

(1)直接插入排序:(稳定排序)     基本思想:将每个待排序的记录,按照其顺序码的大小插入到前面已经排序好的子序列的合适位置(从后向前找合适位置),直到全部插入排序完成为止。     时间复杂度:
平均时间复杂度为O(n^2)。
    
文件初态不同时,直接插入排序所耗费的时间有很大差异。若文件初态为正序,则每个待插入的记录只需要比较一次就能够找到合适的位置插入,故算法的时间复杂度为O(n),这时最好的情况。若初态为反序,则第i个待插入记录需要比较i+1次才能找到合适位置插入,故时间复杂度为O(n^2),这时最坏的情况。

/*
  * 直接插入排序
  */
 static void directInsertSort(int []array){
  int i,j,temp;
        for (i = 1; i < array.length; i++) {
            //待插入元素
            temp = array[i];
            for (j = i-1; j>=0 && array[j]>temp; j--) {
                //将大于temp的往后移动一位
             array[j+1] = array[j];
            }
            array[j+1] = temp;
        }
 }

(2)二分法插入排序(稳定排序) 基本思路:同直接插入排序,只是寻找插入位置的方法不同,使用二分法确定插入位置; 时间复杂度:
平均时间复杂度为O(n^2)。

/*
  * 二分插入排序
  */
 static void binaryInsertSort(int []array){
  int left,right,mid,temp;
  for(int i=0;i<array.length;i++)
  {
   temp=array[i];
   left=0;
   right=i-1;
   mid=0;
   while(left<=right){
    mid=(left+right)/2;
    if(temp<array[mid])
     right=mid-1;
    else {
     left = mid+1;
    }
   }
   for(int j=i-1;j>=left;j--){
    array[j+1]=array[j];
   }
   array[left]=temp;
  }
 }

(3)希尔排序(不稳定排序)
    基本思路:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。该方法实质上是一种分组插入方法。

    时间复杂度:平均时间复杂度为O(nlogn)    

    希尔排序的时间性能优于直接插入排序,原因如下:

  (1)当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。   (2)当n值较小时,n和n2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(n2)差别不大。   (3)在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。   因此,希尔排序在效率上较直接插人排序有较大的改进。

/*
  * 希尔排序
  */
 static void xierInsertSort(int []array){
  int interval=array.length;
  while(true){
   interval=interval/2;
   for(int i=0;i<array.length;i++){
    directInsertSort(array,i,interval);
   }
   if(interval==1)
    break;
  }
 
 }
  /*
  * 直接插入排序
  */
 static void directInsertSort(int []array,int start,int interval){
  int i,j,temp;
        for (i = start; i < array.length; i=i+interval) {
            //待插入元素
            temp = array[i];
            for (j = i-interval; j>=0 && array[j]>temp; j=j-interval) {
                //将大于temp的往后移动interval
             array[j+interval] = array[j];
            }
            array[j+interval] = temp;
        }
 }

(4)直接选择排序(不稳定排序)     
基本思路:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。
    时间复杂度:平均时间复杂度为O(n^2)。

  /*
  * 简单选择排序
  */
 static void simpleSelectSort(int []array){
  int i,j,temp,flag;
        for (i = 0; i < array.length; i++) {
            temp = array[i];
            flag=i;
            for (j = i+1; j<array.length; j++) {
                if(array[j]<temp){
                 temp=array[j];
                 flag=j;
                }
            }
            array[flag]=array[i];
            array[i] = temp;
        }
 }

(5)堆排序(不稳定排序)
    堆的定义下:具有n个元素的序列 (h1,h2,…,hn),当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1) (i=1,2,…,n/2)时称之为堆。
    基本思路:初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个堆,这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。
    时间复杂度:平均时间复杂度为O(nlogn)    

static void buildHeap(int [] array){
  //循环建堆  
        for(int i=0;i<array.length-1;i++){  
            //建堆  
            buildMinHeap(array,array.length-1-i);  
            //交换堆顶和最后一个元素  
            swap(array,0,array.length-1-i);  
            System.out.println(Arrays.toString(array));  
        }  
  }
    //对array数组从0到lastIndex建大根堆
    static void buildMaxHeap(int[] array, int lastIndex){
         //从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(array[biggerIndex]<array[biggerIndex+1]){  
                        //biggerIndex总是记录较大子节点的索引  
                        biggerIndex++;  
                    }  
                }  
                //如果k节点的值小于其较大的子节点的值  
                if(array[k]<array[biggerIndex]){  
                    //交换他们  
                    swap(array,k,biggerIndex);  
                    //将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值  
                    k=biggerIndex;  
                }else{  
                    break;  
                }  
            }
        }
    }
   
    //对array数组从0到lastIndex建小根堆
    static void buildMinHeap(int[] array, int lastIndex){
         //从lastIndex处节点(最后一个节点)的父节点开始
        for(int i=(lastIndex-1)/2;i>=0;i--){
            //k保存正在判断的节点
            int k=i;
            //如果当前k节点的子节点存在  
            while(k*2+1<=lastIndex){
                //k节点的左子节点的索引
                int smallerIndex=2*k+1;
                //如果smallerIndex小于lastIndex,即smallerIndex+1代表的k节点的右子节点存在
                if(smallerIndex<lastIndex){  
                    //若果右子节点的值较小  
                    if(array[smallerIndex]>array[smallerIndex+1]){  
                        //smallerIndex总是记录较小子节点的索引  
                     smallerIndex++;  
                    }  
                }  
                //如果k节点的值大于其较小的子节点的值  
                if(array[k]>array[smallerIndex]){  
                    //交换他们  
                    swap(array,k,smallerIndex);  
                    //将smallerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值小于其左右子节点的值  
                    k=smallerIndex;  
                }else{  
                    break;  
                }  
            }
        }
    }
    //交换
    static void swap(int[] array, int i, int j) {  
        int temp=array[i];  
        array[i]=array[j];  
        array[j]=temp;  
    }

(6)冒泡排序(稳定排序)
    基本思路:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。
    时间复杂度:平均时间复杂度为O(n^2)。

/*
  * 冒泡排序
  */
 static void bubSwapSort(int []array){
  int i,j,temp;
  Boolean flag=false;
        for (i = 0; i < array.length; i++) {
         flag=true;
            for(j=0;j<array.length-i-1;j++){
             if(array[j+1]<array[j])
             {
              temp=array[j+1];
              array[j+1]=array[j];
              array[j]=temp;
              flag=false;
             }
            }
            if(flag)
             break;
        }
 }

(7)快速排序(不稳定排序)
    基本思路:
选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。
    时间复杂度:平均时间复杂度为O(nlogn) 

/*
  * 快速排序
  */
 static void quickSwapSort(int []array){
  if(array.length>0)
   quickSort(array,0,array.length-1);
 }
 static void quickSort(int []array,int start,int end){
  if(start<end){
   int mid=getMiddleIndex(array,start,end);
   quickSort(array,0,mid-1);
   quickSort(array,mid+1,end);
  }
 }
 static int getMiddleIndex(int []array,int start,int end){
  int temp=array[start];
  while(start<end){
   while(start<end&&array[end]>=temp)
    end--;
   array[start]=array[end];
   while(start<end&&array[start]<=temp)
    start++;
   array[end]=array[start];
  }
  array[start]=temp;
  return start;
 }

(8)归并排序(稳定排序)
    基本思路:将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

平均时间复杂度为O(nlogn)

 /*
   * 归并排序
   */
     static void mergeSort(int[] array, int left, int right) {
         if(left<right){
             int middle = (left+right)/2;
             //对左边进行递归
             mergeSort(array, left, middle);
             //对右边进行递归
             mergeSort(array, middle+1, right);
             //合并
             merge(array,left,middle,right);
         }
     }
     static void merge(int[] array, int left, int middle, int right) {
         int[] tempArray = new int[array.length];
         int middleRight = middle+1; //右边的起始位置
         int temp = left;
         int third = left;
         while(left<=middle && middleRight<=right){
             //从两个数组中选取较小的数放入临时数组
             if(array[left]<=array[middleRight]){
                 tempArray[third++] = array[left++];
             }else{
                 tempArray[third++] = array[middleRight++];
             }
         }
         //将剩余的部分放入临时数组
         while(left<=middle){
             tempArray[third++] = array[left++];
         }
         while(middleRight<=right){
             tempArray[third++] = array[middleRight++];
         }
         //将临时数组的排序结果复制到原数组
         while(temp<=right){
          array[temp] = tempArray[temp++];
         }
     }

(9)基数排序(稳定排序)
    基本思路:将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。从最低位开始,依次进行排序,从最低位一直排序到最高位,数列就变成一个有序序列。
    时间复杂度:O(d(n+r)),d为位数,r为基数

/*
    * 基数排序
    */
     static void radixSort(int[] array) {
         //找到最大数,确定位数
         int max = 0;
         int times = 0;
         for (int i = 0; i < array.length; i++) {
             if(max<array[i]){
                 max = array[i];
             }
         }
         while(max>0){
             max = max/10;
             times++;
         }
         //建立数字列表
         List<ArrayList> list = new ArrayList<ArrayList>();
         for (int i = 0; i < 10; i++) {
             ArrayList<Integer> queue = new ArrayList<Integer>();
             list.add(queue);
         }
         int bit_num=0;
         int count = 0;
         for (int i = 0; i < times; i++) {
             for (int j = 0; j < array.length; j++) {
              bit_num = array[j]%(int)Math.pow(10, i+1)/(int)Math.pow(10, i);
                 ArrayList<Integer> queue = list.get(bit_num);
                 queue.add(array[j]);
                 list.set(bit_num,queue);
             }
             //重新调整数组
             count = 0;
             for (int j = 0; j < 10; j++) {
                 while(list.get(j).size()>0){
                     ArrayList<Integer> queue = list.get(j);
                     array[count++] = queue.get(0);
                     queue.remove(0);
                 }
             }
         }
     }

 

参考:

http://www.cnblogs.com/liuling/p/2013-7-24-01.html

http://www.cnblogs.com/Braveliu/archive/2013/01/15/2861201.html

    原文作者:排序算法
    原文地址: https://blog.csdn.net/zlele0326/article/details/51281578
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞