zoukankan      html  css  js  c++  java
  • 算法的六种排序

    一、选择排序法

      简单选择排序是最简单直观的一种算法,基本思想为每一趟从待排序的数据元素中选择最小(或最大)的一个元素作为首元素,直到所有元素排完为止,简单选择排序是不稳定排序。

             for (int i = 0; i < arr.length - 1; i++) {

                int min = i;//每一趟循环比较时,min用于存放较小元素的数组下标,这样当前批次比较完毕最终存放的就是此趟内最小的元素的下标,避免每次遇到较小元素都要进行交换。
                for (int j = i + 1; j < arr.length; j++) {
                    if (arr[j] < arr[min]) {
                        min = j;
                    }
                }
    }

      简单选择排序通过上面优化之后,无论数组原始排列如何,比较次数是不变的;对于交换操作,在最好情况下也就是数组完全有序的时候,无需任何交换移动,在最差情况下,也就是数组倒序的时候,交换次数为n-1次。综合下来,时间复杂度为
    )
    二、冒泡排序
      
      冒泡排序的基本思想是,对相邻的元素进行两两比较,顺序相反则进行交换,这样,每一趟会将最小或最大的元素“浮”到顶端,最终达到完全有序

     
     for (int i = 0; i < arr.length - 1; i++) {
                boolean flag = true;//设定一个标记,若为true,则表示此次循环没有进行交换,也就是待排序列已经有序,排序已然完成。
                for (int j = 0; j < arr.length - 1 - i; j++) {
                    if (arr[j] > arr[j + 1]) {
                        swap(arr,j,j+1);
                        flag = false;
                    }
                }
                if (flag) {
                    break;
                }
            }
      根据上面这种冒泡实现,若原数组本身就是有序的(这是最好情况),仅需n-1次比较就可完成;若是倒序,比较次数为 n-1+n-2+

    ...

    +1=n(n-1)/2,交换次数和比较次数等值。所以,其时间复杂度依然为O(n

    2

    )。综合来看,冒泡排序性能还还是稍差于上面那种选择排序的。
    三、插入排序
      直接插入排序基本思想是每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完所有元素为止
    for (int i = 1; i < arr.length; i++) {
                int j = i;
                while (j > 0 && arr[j] < arr[j - 1]) {
                    swap(arr,j,j-1);
                    j--;
                }
            }
     
    
    

      简单插入排序在最好情况下,需要比较n-1次,无需交换元素,时间复杂度为O(n);在最坏情况下,时间复杂度依然为O(n2)。但是在数组元素随机排列的情况下,插入排序还是要优于上面两种排序的。

    
    

    四、希尔排列

      希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
    public class ShellSort {
     9     public static void main(String []args){
    10         int []arr ={1,4,2,7,9,8,3,6};
    11         sort(arr);
    12         System.out.println(Arrays.toString(arr));
    13         int []arr1 ={1,4,2,7,9,8,3,6};
    14         sort1(arr1);
    15         System.out.println(Arrays.toString(arr1));
    16     }
    17 
    18     /**
    19      * 希尔排序 针对有序序列在插入时采用交换法
    20      * @param arr
    21      */
    22     public static void sort(int []arr){
    23         //增量gap,并逐步缩小增量
    24        for(int gap=arr.length/2;gap>0;gap/=2){
    25            //从第gap个元素,逐个对其所在组进行直接插入排序操作
    26            for(int i=gap;i<arr.length;i++){
    27                int j = i;
    28                while(j-gap>=0 && arr[j]<arr[j-gap]){
    29                    //插入排序采用交换法
    30                    swap(arr,j,j-gap);
    31                    j-=gap;
    32                }
    33            }
    34        }
    35     }
    36 
    37     /**
    38      * 希尔排序 针对有序序列在插入时采用移动法。
    39      * @param arr
    40      */
    41     public static void sort1(int []arr){
    42         //增量gap,并逐步缩小增量
    43         for(int gap=arr.length/2;gap>0;gap/=2){
    44             //从第gap个元素,逐个对其所在组进行直接插入排序操作
    45             for(int i=gap;i<arr.length;i++){
    46                 int j = i;
    47                 int temp = arr[j];
    48                 if(arr[j]<arr[j-gap]){
    49                     while(j-gap>=0 && temp<arr[j-gap]){
    50                         //移动法
    51                         arr[j] = arr[j-gap];
    52                         j-=gap;
    53                     }
    54                     arr[j] = temp;
    55                 }
    56             }
    57         }
    58     }
    59     /**
    60      * 交换数组元素
    61      * @param arr
    62      * @param a
    63      * @param b
    64      */
    65     public static void swap(int []arr,int a,int b){
    66         arr[a] = arr[a]+arr[b];
    67         arr[b] = arr[a]-arr[b];
    68         arr[a] = arr[a]-arr[b];
    69     }
    70 }
         希尔排序中对于增量序列的选择十分重要,直接影响到希尔排序的性能。我们上面选择的增量序列{n/2,(n/2)/2...1}(希尔增量),其最坏时间复杂度依然为O(n2)
     
    五、堆排序
      堆排序是利用这种数据结构而设计的一种排序算法,堆是完全二叉树,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。首先简单了解下堆结构。

       总结堆排序:

       a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;

      b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;

      c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。


    public class HeapSort {
        public static void main(String []args){
            int []arr = {9,8,7,6,5,4,3,2,1};
            sort(arr);
            System.out.println(Arrays.toString(arr));
        }
        public static void sort(int []arr){
            //1.构建大顶堆
            for(int i=arr.length/2-1;i>=0;i--){
                //从第一个非叶子结点从下至上,从右至左调整结构
                adjustHeap(arr,i,arr.length);
            }
            //2.调整堆结构+交换堆顶元素与末尾元素
            for(int j=arr.length-1;j>0;j--){
                swap(arr,0,j);//将堆顶元素与末尾元素进行交换
                adjustHeap(arr,0,j);//重新对堆进行调整
            }
    
        }
    
        /**
         * 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
         * @param arr
         * @param i
         * @param length
         */
        public static void adjustHeap(int []arr,int i,int length){
            int temp = arr[i];//先取出当前元素i
            for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
                if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
                    k++;
                }
                if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
                    arr[i] = arr[k];
                    i = k;
                }else{
                    break;
                }
            }
            arr[i] = temp;//将temp值放到最终的位置
        }
    
        /**
         * 交换元素
         * @param arr
         * @param a
         * @param b
         */
        public static void swap(int []arr,int a ,int b){
            int temp=arr[a];
            arr[a] = arr[b];
            arr[b] = temp;
        }
    }

    六、归并排序

                                                 ----------------------归并之分治

      上层铺盖颜色的部分是“分”    下层无颜色部分是“治”

      使用分治法的两路合并排序算法:

      就是将待排序的元素序列一分为二,得到长度基本相等的两个子序列,分别排序。如果子序列较长,还可继续细分,直到子序列的长度不超过1为止。当分解所得的子序列已排列有序时,将两个有序子序列合并成一个有序子序列,得到原问题的解。

                    -------------------归并之合并 

    合并方法:

    比较两序列中的最小值,输出其中较小者,然后重复此过程,直到其中一个队列为空时,

    如果另一个队列还有元素没有输出,则将剩余元素依次输出

    #include<stdio.h>
    #define N 100
    int merge(int *a, int left,int mid,int right)
    {
      int i,j,k=0;
      int b[N]={0};
      i=left;
      j=mid+1;
      while(i<=mid&&j<=right) /*把两个序列中小的部分先输入到中间数组*/
      {
        if(a[i]<a[j])
          b[k++]=a[i++];
        else
          b[k++]=a[j++];
      }
      while(i<=mid) /*没有输完的序列剩下的依次输入到中间数组*/
        b[k++]=a[i++];
      while(j<=right)
        b[k++]=a[j++];
      for(i=0;i<k;i++) /*将排序好的出处在中间数组里的序列输入到a数组*/
        a[left++]=b[i];
      return 0;
    }
    int mergesort(int *a,int left,int right) /*将序列划分为等大的两部分再调用排序*/
    {
      int i,j,mid;
      if(right-left>=1)
      {
        mid=(left+right)/2;
        mergesort(a,left,mid);
        mergesort(a,mid+1,right);
        merge(a,left,mid,right); /*调用排序*/
      }
      return 0;
    }
    int main()
    {
      int a[N]={0},i,n;
      printf("please input the length of the list: ");
      scanf("%d",&n);
      printf("please input the number of the list: ");
      for(i=0;i<n;i++)
        scanf("%d",&a[i]);
      mergesort(a,0,n-1);
      printf("the sort of the list is : ");
      for(i=0;i<n;i++)
        printf("%d ",a[i]);
      printf(" ");
      return 0;
    }传统的归并排序最好情况复杂度是O(nlogn)最坏情况复杂度是O(nlogn)     经过一些改进的归并排序最好情况复杂度是O(n),最坏情况是O(nlogn)

     


  • 相关阅读:
    DIV 设置垂直居中
    JavaScript--什么是函数
    JavaScript--引用JS外部文件
    JavaScript--如何插入JS
    CSS-类和ID选择器的区别
    CSS-ID选择器
    CSS类选择器
    CSS样式介绍
    HTML--使用mailto在网页中链接Email地址
    HTML--form表单中的label标签
  • 原文地址:https://www.cnblogs.com/lumc5/p/11245229.html
Copyright © 2011-2022 走看看