排序算法JAVA实现二

时间复杂度为 O(n*log(n))的算法:归并排序、快速排序、堆排序、希尔排序

题: 对于一个int数组,请编写一个排序算法,对数组元素排序。
给定一个int数组A及数组的大小n,请返回排序后的数组。
测试样例:
  [1,2,3,5,2,3],6
  [1,2,2,3,3,5]

一,归并排序

  归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
  
  归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]

归并操作的工作原理如下:
  第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
  第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
  第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
  第四步:重复步骤3直到某一指针超出序列尾,将另一序列剩下的所有元素直接复制到合并序列尾

JAVA代码实现:

package Sort;
import java.util.*;
public class MergeSort {
     public int[] mergeSort(int[] A, int n ) {
            process(A,0,n-1);   
            return A;
        }  

     void process(int[] A,int l,int r){
            int mid=(l+r)/2;
            if(l < r) {  
              process(A,l,mid);
              process(A,mid+1,r);   
              merge(A,l,mid,r);              
            }
        }  

     void merge(int[] nums,int low,int mid, int high ){
           int[] temp = new int[high - low + 1];  
           int i = low;// 左指针  
           int j = mid + 1;// 右指针  
           int k = 0;    
           // 把较小的数先移到新数组中  
           while (i <= mid && j <= high) {  
               if (nums[i] < nums[j]) {  
                   temp[k++] = nums[i++];  
               } else {  
                   temp[k++] = nums[j++];  
               }  
           }   
          // 把左边剩余的数移入数组  
          while (i <= mid) {  
              temp[k++] = nums[i++];  
           }  
         // 把右边边剩余的数移入数组  
          while (j <= high) {  
             temp[k++] = nums[j++];  
         }  
         // 把新数组中的数覆盖nums数组  
         for (int k2 = 0; k2 < temp.length; k2++) {  
           nums[k2 + low] = temp[k2];  
          }  
       }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] A = { 1, 2,  3, 5, 2, 6};  
        int n=6;
        MergeSort ms = new MergeSort();
        ms.mergeSort(A, n);  
        System.out.println(Arrays.toString(A)); 
    }

}

二,快速排序

  快速排序(Quicksort)是对冒泡排序的一种改进。
  快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

一趟快速排序的算法是:
 1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
 2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
 3)从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于key的值A[j],将A[j]和A[i]互换;
 4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
 5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。

JAVA实现:

package Sort;
import java.util.*;
public class QuickSort {
    public int[] quickSort(int[] A, int n) {
        // write code here
        if (A == null || n == 0) return null;
        Sort(A,0,n-1);
        return A;
    }

    void Sort(int[] A,int left,int right){
        if(left<right){
            int q=Partition(A,left,right);
            Sort(A,left,q-1);
            Sort(A,q+1,right);
        }
    }

    int Partition(int[] A,int left,int right){          
           int key = A[left];  
           while (left < right) { 
               //由后开始向前搜索,找到第一个小于key的值A[right]
               while (left < right && A[right] >= key) --right;  
               //交换
               A[left] = A[right];  
               while (left < right &&  A[left] <= key) ++left;  
               A[right] = A[left];  
           }   
           A[left] = key;     
           return left; 
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
            int[] A = { 1, 2,  3, 5, 2, 6};  
            int n=6;
            QuickSort qs = new QuickSort();
            qs.quickSort(A, n);  
            System.out.println(Arrays.toString(A)); 
    }
}

三,堆排序

  堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
  
这里写图片描述
 
 用大根堆排序的基本思想
  ① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
  ② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
  ③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
……
直到无序区只有一个元素为止

JAVA实现:

package Sort;
import java.util.Arrays;

public class HeapSort {
        public int[] heapSort(int[] A, int n) {
            // write code here
            if(n < 2) return A;          
            for(int i = 0; i < n; i++) {      
                adjust(A, 0, n - i);               
                swap(A, 0, n - 1 - i);        
            }                  
            return A;
        }  

        void adjust(int[] A, int root, int size) { 
            if(root*2 + 1 < size) {      
                adjust(A, root * 2 + 1, size);       
                }         
            if(root * 2 + 2 < size) {      
                adjust(A, root * 2 + 2, size);    
                }         
            int MAX = root;   
            if(root * 2 + 1 < size) {      
                if(A[root * 2 + 1] > A[root]) {         
                    MAX = root * 2 + 1;            
                    }        
            }         
            if(root * 2 + 2 < size) {      
                if(A[root * 2 + 2] > A[MAX]) {         
                    MAX = root * 2 + 2;           
                    }       
                }        
                swap(A, root, MAX);   
            }   

        void swap(int[] A, int a, int b) {  
            if(a == b) return;            
            int temp = A[a];   
            A[a] = A[b];    
            A[b] = temp;   
            }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] A = { 1, 2,  3, 5, 2, 6};  
        int n=6;
        HeapSort hs = new HeapSort();
        hs.heapSort(A, n);  
        System.out.println(Arrays.toString(A));
    }
}

四,希尔排序

  希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。
  希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

  希尔排序是基于插入排序的以下两点性质而提出改进方法的:插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。

 该方法实质上是一种分组插入方法:
  相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比[2] 较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。
  一般的初次取序列的一半为增量,以后每次减半,直到增量为1。

这里写图片描述

JAVA实现:

package Sort;
import java.util.Arrays;

public class ShellSort {
    public int[] shellSort(int[] A, int n) {
        // write code here
        for(int gap = n/2 ;
            gap >= 1; gap /= 2){      
            for(int i = gap; i < n; i++){         
                for(int j = i - gap ; j >= 0 ; j -= gap){           
                    if(A[j] > A[j + gap]){                
                        int temp = A[j];                 
                        A[j] = A[j + gap];                
                        A[j + gap] = temp;            
                    }           
                }      
            }
        }
        return A;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] A = { 1, 2,  3, 5, 2, 6};  
        int n=6;
        ShellSort ss = new ShellSort();
        ss.shellSort(A, n);  
        System.out.println(Arrays.toString(A));
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值