各种排序算法大合集

各种算法的比较:
各种排序算法大合集
快速排序:
各种排序算法大合集

希尔(Shell)排序:
要点
希尔(Shell)排序又称为缩小增量排序,它是一种插入排序。它是直接插入排序算法的一种威力加强版。

希尔排序的基本思想是:

把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。
随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到 1 时,整个数据合成为一组,构成一组有序记录,则完成排序。

我们来通过演示图,更深入的理解一下这个过程。

在上面这幅图中:
各种排序算法大合集

初始时,有一个大小为 10的无序序列。

在第一趟排序中,我们不妨设 gap1 = N / 2 = 5,即相隔距离为 5 的元素组成一组,可以分为 5 组。

接下来,按照直接插入排序的方法对每个组进行排序。

在第二趟排序中,我们把上次的 gap缩小一半,即 gap2 = gap1 / 2 = 2 (取整数)。这样每相隔距离为 2的元素组成一组,可以分为 2 组。

按照直接插入排序的方法对每个组进行排序。

在第三趟排序中,再次把 gap缩小一半,即gap3 = gap2 / 2 = 1。这样相隔距离为 1 的元素组成一组,即只有一组。

按照直接插入排序的方法对每个组进行排序。此时,排序已经结束。

需要注意一下的是,图中有两个相等数值的元素 5 和 5 。我们可以清楚的看到,在排序过程中,两个元素位置交换了。

所以,希尔排序是不稳定的算法。

朕的实现方法在此:

//测试类:
//注意:com.sxt.xxx 是包名
package org.sxt.test;

import java.util.Arrays;
import java.util.Scanner;

import com.sxt.b.BubbleSort;
import com.sxt.b.InsertSort;
import com.sxt.b.MergeSort;
import com.sxt.b.QuickSort;
import com.sxt.b.SelectSort;
import com.sxt.b.ShellSort;
import com.sxt.win.Show;

public class TestSort {

	public static void main(String[] args) {
		//1.给出无序数组
		int arr[]= {72,6,57,88,60,42,83,73,48,85};
		//2.输出无序数组
		System.out.println("原数组:"+Arrays.toString(arr));
		
		while(true) {
	     //3.排序
        Show.show();
		Scanner sc = new Scanner(System.in);
		int select = sc.nextInt();
		switch(select)
		{
		   case 1:QuickSort.quickSort(arr);break;
		   case 2:BubbleSort.bulleSort(arr);break;
		   case 3:SelectSort.select(arr);break;
		   case 4:InsertSort.insertSort(arr);break;
		   case 5:ShellSort.shellSort(arr);break;
		   case 6:MergeSort.merge_sort(arr);break;
		}
		//4.输出有序数列
        System.out.println(Arrays.toString(arr));
	  }
	}

}

package com.sxt.win;


public class Show {
	public static void show() {
		System.out.println("请选择排序方式:\n1.快速排序\n2.冒泡排序\n3.选择排序\n4.插入排序\n5.希尔遍历\n6.归并排序");
	}
}
//冒泡排序
package com.sxt.b;

public class BubbleSort {
	//冒泡排序算法
	public static void bulleSort(int[] arr) {
		for(int i=0;i<arr.length-1;i++)//扫描次数
		{
			for(int j=0;j<arr.length-1-i;j++) {
				if(arr[j]>arr[j+1]) {
					int temp=arr[j];
				    arr[j]=arr[j+1];
				    arr[j+1]=temp;
				}
			}
		}
		
	}
}

//插入排序
package com.sxt.b;

public class InsertSort {
	public static void insertSort(int[] arr) {
		/*遍历所有的数字看哪个比前面的小,
        *如果小那就说明前面至少有一个比当前元素小的
        *把当前元素塞到刚好比当前元素的小的元素前面,那么它后边的都要往后排一个
        */		
		for(int i=1;i<arr.length;i++) {
			//如果当前数字比前一个数字小
			if(arr[i]<arr[i-1]) {
				//先把当前元素存起来
				int temp=arr[i];
				//遍历当前元素前面的元素
				for(int j=i-1;j>0&&temp<arr[j];j--) {
					//把前一个数字赋给后一个数字
					arr[j+1]=temp;
				}
			}
		}
	}

}

//归并排序
package com.sxt.b;

public class MergeSort {
	public static void merge_sort(int[] arr) {
		  mergesort(arr, 0, arr.length - 1);
		}
		public static void mergesort(int[] arr,int left, int right) {
		  if(left < right) return;  
		  int middle = (left+right) / 2;
		  mergesort(arr, left, middle);
		  mergesort(arr, middle + 1, right);
		  mergeArr(arr, left, middle, right);//将左右两部分合并(左右两部分已经在递归中各自排好了序)
		}
		public static void mergeArr(int[] arr, int left, int middle, int right) {
		  int[] temp = new int[right - left + 1];//开辟新数组
		  int i = left, j = middle + 1, k = 0;
		  while(i <= middle && j <= right) {//经过这个循环后最多有一个数组有残余
		    temp[k++] = arr[i] < arr[j]? arr[i++] : arr[j++];
		  }
		  while(i <= middle) {//如果有残余加入到temp中
		    temp[k++] = arr[i++];
		  }
		  while(j <= right) {//如果有残余加入到temp中
		    temp[k++] = arr[j++];
		  }
		  // 将辅助数组数据写入原数组
		  int index = 0;
		  while(left <= right) {
		    arr[left++] = temp[index++];
		  }
		}
}

//快速排序
package com.sxt.b;
public class QuickSort {
	//分区函数
	private static int partition(int[] arr,int low,int high) {
		//1.指定左指针i和右针织j
		int i=low;
		int j=high;
		//2.将第一个元素作为基准,挖坑带走
		int x=arr[low];
		//3.使用循环实现分区操作
        while(i<j) {
        	//1.从右至左移动j,找到第一个小于基准值的元素,arr[j],挖走
        	while(arr[j]>x&&i<j) {
        		j--;
        	}
        	//2.将arr[j]填入左边坑的位置,左指针i向右移动一个单位,指针右移一位i++
        	if(i<j) {
        		arr[i]=arr[j];
        		i++;
        	}
        	//3.从左向右移动i,找到第一个大于基准的元素arr[i]
        	while(arr[i]<x&&i<j) {
        		i++;
        	}       	
        	//4.将左侧找到的元素填入到右边的坑内,j--
        	if(i<j) {
        		arr[j]=arr[i];
        		j--;
        	}
        }
		//4.使用基准填坑,这是基准值的最终位置
		arr[i]=x;
		//5.返回基准的位置、
		return i;
	}
	//快速排序算法
	private static void quickSort(int[] arr,int low, int high) {//递归何时结束(low<high),所剩元素大于两个
		if(low<high) {
		//分区操作,将一个数组分成两个分区,并返回分区索引
		int index=partition(arr,low,high);
		//将左分区进行快排
		quickSort(arr,low,index-1);
		//将右分区进行快排
		quickSort(arr,index+1,high);
	}
}
	public static void quickSort(int[] arr) {
		int low=0;
		int high=arr.length-1;
		quickSort(arr,low,high);
	}
}

//选择排序
package com.sxt.b;

public class SelectSort {
	public static void select(int[] arr) {
		for(int i=0;i<arr.length-1;i++)
			for(int j=i+1;j<arr.length;j++)
			{
				if(arr[i]>arr[j])
				{
					int temp=arr[i];
					arr[i]=arr[j];
					arr[j]=temp;
				}
			}
	}
    
}

//希尔排序
package com.sxt.b;

import java.util.Arrays;

public class ShellSort {
	public static void shellSort(int[] arr) {
		int k=0;
		//遍历所有的步长(步长每次减半)
		for(int d=arr.length/2;d>0;d/=2)
		{
			//遍历所有组
			for(int i=d;i<arr.length;i++) {
				//遍历本组中的元素(相隔为d的元素是一组)
				for(int j=i-d;j>=0;j-=d)
				{
					//如果当前元素大于加上步长后的元素则交换位置
					if(arr[j]>arr[j+d]) {
						int temp=arr[j];
						arr[j]=arr[j+d];
						arr[j+d]=temp;
					}
				}
			}
			k++;
			System.out.println("第"+k+"次步长折半遍历"+Arrays.toString(arr));
		}
	}

}