排序

http://www.runoob.com/w3cnote/sort-algorithm-summary.html

图解排序算法(二)之希尔排序 - https://www.cnblogs.com/chengxiao/p/6104371.html

一. 冒泡排序(BubbleSort)

从后向前比较相邻的两个数,较大的数下沉,较小的数冒起来(就交换位置)。平均时间复杂度:n+(n-1)+...+1 = (1+n)*n/2 -> O(n^2)

public static void BubbleSort(int [] arr){
   int temp;//临时变量
   boolean flag;//是否交换的标志——优化,已完成排序时不再循环
   for(int i=0; i<arr.length-1; i++){   //表示趟数,一共arr.length-1次。

       flag = false;
       for(int j=arr.length-1; j>i; j--){

           if(arr[j] < arr[j-1]){
               temp = arr[j];
               arr[j] = arr[j-1];
               arr[j-1] = temp;
               flag = true;
           }
       }
       if(!flag) break;
   }
}

二. 选择排序(SelctionSort)


在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;第二次遍历n-2个数,找到最小的数值与第二个元素交换。

选择排序把最小值存在临时变量,遍历完后与数组里原元素互换(第一层循环);冒泡排序每次比较后都会互换(第二层循环中,把比较结果片段性的保存下来,虽然下次仍要比较)。

平均时间复杂度:n+(n-1)+...+1 = (1+n)*n/2 -> O(n^2)

public static void select_sort(int array[],int lenth){
   for(int i=0;i<lenth-1;i++){
       int minIndex = i;
       for(int j=i+1;j<lenth;j++){
          if(array[j]<array[minIndex]){
              minIndex = j;
          }
       }
       if(minIndex != i){
           int temp = array[i];
           array[i] = array[minIndex];
           array[minIndex] = temp;
       }
   }
}

三. 堆排序(HeapSort)(选择排序)

堆是一棵顺序存储的完全二叉树,完全二叉树中所有非终端节点的值均不大于(或不小于)其左、右孩子节点的值(小根堆,大根堆)。


//构建最小堆
public static void MakeMinHeap(int a[], int n){
 for(int i=(n-1)/2 ; i>=0 ; i--){
     MinHeapFixdown(a,i,n);
 }
}
//从i节点开始调整,n为节点总数 从0开始计算 i节点的子节点为 2*i+1, 2*i+2  
public static void MinHeapFixdown(int a[],int i,int n){

   int j = 2*i+1; //子节点
   int temp = 0;

   while(j<n){
       //在左右子节点中寻找最小的
       if(j+1<n && a[j+1]<a[j]){   
           j++;
       }

       if(a[i] <= a[j])
           break;

       //较大节点下移
       temp = a[i];
       a[i] = a[j];
       a[j] = temp;

       i = j;
       j = 2*i+1;
   }
}

 

public static void MinHeap_Sort(int a[],int n){
  int temp = 0;
  MakeMinHeap(a,n);

  for(int i=n-1;i>0;i--){
      temp = a[0];
      a[0] = a[i];
      a[i] = temp; 
      MinHeapFixdown(a,0,i);
  }     
}

四. 插入排序(Insertion Sort)


在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。(n从2开始)

平均时间复杂度: 1+...+(n-1)= (1+n-1)*(n-1)/2 -> O(n^2)

public static void  insert_sort(int array[],int lenth){
   int temp;
   for(int i=0;i<lenth-1;i++){
       for(int j=i+1;j>0;j--){
           if(array[j] < array[j-1]){
               temp = array[j-1];
               array[j-1] = array[j];
               array[j] = temp;
           }else{         //不需要交换
               break;
           }
       }
   }
}

五. 希尔排序(Shell Sort)


在要排序的一组数中,根据某一增量分为若干子序列,并对子序列分别进行插入排序。

初始增量使用gap=length/2=10/2=5,即每组子序列的元素两两之间的主序列中下标的增量(5)。分组如图:

然后逐渐将增量减小,并重复上述过程。

每个子序列做插入排序,再按gap=gap/2=2分子序列

直至增量为1,此时数据序列基本有序,最后进行插入排序

public static void shell_sort(int array[],int lenth){
   int temp = 0;
   int incre = lenth;
   while(true){
       incre = incre/2;
       for(int k = 0;k<incre;k++){    //根据增量分为若干子序列
           for(int i=k+incre;i<lenth;i+=incre){
               for(int j=i;j>k;j-=incre){
                   if(array[j]<array[j-incre]){
                       temp = array[j-incre];
                       array[j-incre] = array[j];
                       array[j] = temp;
                   }else{
                       break;
                   }
               }
           }
       }
       if(incre == 1){
           break;
       }
   }
}

六. 快速排序(Quicksort)


先从数列中取出一个数作为key值;将比这个数小的数全部放在它的左边,大于或等于它的数全部放在它的右边;对左右两个小数列重复第二步,直至各区间只有1个数。

public static void quickSort(int a[],int l,int r){//初始值:0,length
     if(l>=r)
       return;
     int i = l; int j = r; int key = a[l];//选择第一个数为key
     while(i<j){
         while(i<j && a[j]>=key)//从j处向左找第一个小于key的值
             j--;//j以右的都比key大
         if(i<j){
             a[i] = a[j]; //原a[i]保存在key;而a[j]的位置可以认为已无效
             i++;
         }
         while(i<j && a[i]<key)//从i处向右找第一个大于或等于key的值
             i++;//i以左的都比key小
         if(i<j){
             a[j] = a[i];//无效a[j]的位置放置此时a[i]的值;而a[i]的位置可以认为已无效
             j--;
         }
     }
     //i == j
     a[i] = key;//a[i]即a[j]的无效位置填回key
     quickSort(a, l, i-1);//递归调用
     quickSort(a, i+1, r);//递归调用
 }

七. 归并排序(Merge Sort)


通过先递归的分解数列,再合并数列完成了归并排序。

public static void merge_sort(int a[],int first,int last,int temp[]){
//(int)(first+first+1)/2 = middle(f,f+1) = first (同last)
if(first < last){ int middle = (first + last)/2; merge_sort(a,first,middle,temp);//左半部分排好序 merge_sort(a,middle+1,last,temp);//右半部分排好序 mergeArray(a,first,middle,last,temp); //合并左右部分 } }
//if( first =0;last=8;length = 9)
//merge_sort(0,4):{merge_sort(0,2){merge_sort(0,1),merge_sort(2,2)}+merge_sort(3,4)}
//merge_sort(5,8)-{merge_sort(5,6)+merge_sort(6,8){merge_sort(6,7)+merge_sort(8,8)}}

 递归函数

public static void mergeArray(int a[],int first,int middle,int end,int temp[]){   
//last(0)=middle(0)+1;middle(0)=first(0)
int i = first; int m = middle; int j = middle+1; int n = end; int k = 0;
//i = first = 0; m = middle = 0; j = n = 1 ok
 //i = first = 0; n=8(or9); m = middle =4; j=5;
//比较2个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。
while(i<=m && j<=n){ if(a[i] <= a[j]){ // temp[k] = a[i]; i++; }else{ temp[k] = a[j]; j++; }
    k++; }
while(i<=m){ temp[k] = a[i]; k++; i++; } while(j<=n){ temp[k] = a[j]; k++; j++; } for(int ii=0;ii<k;ii++){ a[first + ii] = temp[ii]; } }

mergeArray:length=end-first=n; O(n)

无mergeArray的merge_sort:log2n+1

综合O(n*lgn)

八. 基数排序(RadixSort)


BinSort想法非常简单,首先创建数组A[MaxValue];然后将每个数放到相应的位置上(例如17放在下标17的数组位置);最后遍历数组,即为排序后的结果。

问题: 当序列中存在较大值时,BinSort 的排序方法会浪费大量的空间开销。

RadixSort

基数是10

public static void RadixSort(int A[],int temp[],int n,int k,int r,int cnt[]){
   //A:原数组
   //temp:临时数组
   //n:序列的数字个数
   //k:最大的位数2
   //r:基数10
   //cnt:存储bin[i]的个数
   for(int i=0 , rtok=1; i<k ; i++ ,rtok = rtok*r){
       //初始化
       for(int j=0;j<r;j++){
           cnt[j] = 0;
       }
       //计算每个箱子的数字个数
       for(int j=0;j<n;j++){
           cnt[(A[j]/rtok)%r]++;
       }
       //cnt[j]的个数修改为前j个箱子一共有几个数字
       for(int j=1;j<r;j++){
           cnt[j] = cnt[j-1] + cnt[j];
       }
       for(int j = n-1;j>=0;j--){      //重点理解
           cnt[(A[j]/rtok)%r]--;
           temp[cnt[(A[j]/rtok)%r]] = A[j];
       }
       for(int j=0;j<n;j++){
           A[j] = temp[j];
       }
   }
}

 

posted @ 2018-03-14 10:09  wzbin  阅读(177)  评论(0编辑  收藏  举报