一、希尔排序
希尔排序是插入排序算法的一个改进,比如[5,4,3,2,1,0]这种倒序序列,数组末端的0要回到首位置很是费劲。希尔排序是通过自定义控制增量来将一组数据分成若干组,对每个组内元素先进行插入排序,然后再控制增量变小使每个组内的元素越来越多,当增量减小至1时,算法终止,排序就完成了。
比如[5,4,3,2,1]如果直接用插入排序,外层循环会从4开始以增量1一步步扩大有序序列。
而使用希尔排序,我们可以控制增量gap = arr.length/2 = 5/2 = 2 . 那么 最终会将此数据分为三组 [5,3][4,2][3,1],这样先在三组组内分别进行插入排序,之后再缩小gap = gap /2 =1, 此时再重复上述操作并且发现数据已经宏观上有序,就无需大量的移动操作了。这里选择的增量arr.length/2 是常用的但不是最优的,关于这个增量选择是一个数学难题。
希尔排序算法图解:图解排序算法(二)之希尔排序 - dreamcatcher-cx - 博客园
下面贴出代码:
public static void sort(int []arr){
//增量gap,并逐步缩小增量
for(int gap=arr.length/2;gap>0;gap/=2){
//从第gap个元素,逐个对其所在组进行直接插入排序操作
for(int i=gap;i<arr.length;i++){
int j = i;
while(j-gap>=0 && arr[j]<arr[j-gap]){
//插入排序采用交换法
swap(arr,j,j-gap);
j-=gap;
}
}
}
}
public static void swap(int []arr,int a,int b){
arr[a] = arr[a]+arr[b];
arr[b] = arr[a]-arr[b];
arr[a] = arr[a]-arr[b];
}
二、归并排序
归并排序是一个递归算法的例子。它把数据通过递归一步步进行二分,然后再通过合并程序对分后的数据进行排序和合并,一步步合并成原数据大小。
具体图解和算法见链接:图解排序算法(四)之归并排序 - dreamcatcher-cx - 博客园
代码:
public static void MergeSort(int []arr){
int []temp = new int[arr.length];//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
RecMergeSort(arr,0,arr.length-1,temp);
}
private static void RecMergeSort(int[] arr,int left,int right,int []temp){
if(left<right){
int mid = (left+right)/2;
RecMergeSort(arr,left,mid,temp);//左边归并排序,使得左子序列有序
RecMergeSort(arr,mid+1,right,temp);//右边归并排序,使得右子序列有序
merge(arr,left,mid,right,temp);//将两个有序子数组合并操作
}
}
private static void merge(int[] arr,int left,int mid,int right,int[] temp){
int i = left;//左序列指针
int j = mid+1;//右序列指针
int t = 0;//临时数组指针
while (i<=mid && j<=right){
if(arr[i]<=arr[j]){
temp[t++] = arr[i++];
}else {
temp[t++] = arr[j++];
}
}
while(i<=mid){//将左边剩余元素填充进temp中
temp[t++] = arr[i++];
}
while(j<=right){//将右序列剩余元素填充进temp中
temp[t++] = arr[j++];
}
t = 0;
//将temp中的元素全部拷贝到原数组中
while(left <= right){
arr[left++] = temp[t++];
}
}
三、堆排序
堆排序是利用了数据结构堆设计的一种排序算法。它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。
堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。
具体图解过程:图解排序算法(三)之堆排序 - dreamcatcher-cx - 博客园
代码:
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){
arr[a] = arr[a] + arr[b];
arr[b] = arr[a] - arr[b];
arr[a] = arr[a] - arr[b];
}
}
四、快速排序
快速排序是速度最快的高级排序算法,实至名归。不过这只是针对大量且通常无需的数据集合而言,如果数据集合很小(100个元素或者更少),或者数据是相对有序的,那就需要采取基础排序算法了。
它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
具体图解:图解排序算法(五)之快速排序——三数取中法 - dreamcatcher-cx - 博客园
public class QuickSort {
public static void main(String[] args) {
int[] arr = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
quickSort(arr, 0, arr.length - 1);
System.out.println("排序结果:" + Arrays.toString(arr));
}
/**
* @param arr
* @param left 左指针
* @param right 右指针
*/
public static void quickSort(int[] arr, int left, int right) {
if (left < right) {
//获取枢纽值,并将其放在当前待处理序列末尾
dealPivot(arr, left, right);
//枢纽值被放在序列末尾
int pivot = right - 1;
//左指针
int i = left;
//右指针
int j = right - 1;
while (true) {
while (arr[++i] < arr[pivot]) {
while (j > left && arr[--j] > arr[pivot]) {
if (i < j) {
swap(arr, i, j);
} else {
break;
}
}
if (i < right) {
swap(arr, i, right - 1);
}
quickSort(arr, left, i - 1);
quickSort(arr, i + 1, right);
}
}
/**
* 处理枢纽值
*
* @param arr
* @param left
* @param right
*/
public static void dealPivot(int[] arr, int left, int right) {
int mid = (left + right) / 2;
if (arr[left] > arr[mid]) {
swap(arr, left, mid);
}
if (arr[left] > arr[right]) {
swap(arr, left, right);
}
if (arr[right] < arr[mid]) {
swap(arr, right, mid);
}
swap(arr, right - 1, mid);
}
/**
* 交换元素通用处理
*
* @param arr
* @param a
* @param b
*/
private static void swap(int[] arr, int a, int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}