归并排序
概括为一句话:将整体分为两个部分分别排序,然后择优(依次选择较小的插入或较大的)合并新的有序整体。这个过程本身就是递归,当只剩下一个元素的时候也就相当于排好序了。
import java.util.Scanner;
public class digui_MergeSort {
public static void main(String[] args) {
int n;
int []a =new int[1000];
Scanner in= new Scanner(System.in);
n=in.nextInt();
for (int i=0;i<n;i++)
a[i]=in.nextInt();
new digui_MergeSort().MergeSort(a,0,n-1);
for(int i=0;i<n;i++) {
System.out.print(a[i]+" ");
}
}
public void MergeSort(int []a,int low,int high) {
int mid=0;
while(low<high) {
mid=low+(high-low)/2;//分成两个部分,分别排序
MergeSort(a,low,mid);
MergeSort(a,mid+1,high);
Merge(a,low,mid,high);//合并
return;
}
}
private void Merge(int[] a, int low, int mid, int high) {
// TODO Auto-generated method stub
int i=low,j=mid+1,k=0;
int []b = new int[high-low+1];
while(i<=mid&&j<=high) {
if(a[i]<=a[j]) {//选择较小的插入
b[k++]=a[i++];
}else {
b[k++]=a[j++];
}
}
while(i<=mid) {
b[k++]=a[i++];
}
while(j<=high) {
b[k++]=a[j++];
}
for(int x=0,m=low;m<=high;m++) {
a[m]=b[x++];
}
}
}
希尔排序
希尔排序的实质就是分组插入排序,该方法又称缩小增量排序,因DL.Shell于1959年提出而得名。
该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。
import java.util.Scanner;
public class shellsort {
public static void main(String[] args) {
int n;//数据个数
int data[];//需排序的数组
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
data = new int[n];
for (int i = 0; i < n; i++)
data[i] = sc.nextInt();
int d[] = { 5, 3, 1 };//默认依次分割为5,3,1组排序。也可以自己输入d数组但最后一定要有1(回归到插入排序)。
ShellSort(data, d);
for (int i = 0; i < n - 1; i++)
System.out.print(data[i] + " ");
System.out.println(data[n - 1]);
}
private static void ShellSort(int[] data, int[] d) {
int f = 0;
for (int i = 0; i < d.length; i++) {
int h = d[i];//第i轮分为h组,也就在原数组每隔h个取个元素
for (int j = h; j < data.length; j++) {//这个for里面就是插入排序了
if (data[j] < data[j - h]) {
int temp = data[j];
if (f == 1)//控制格式
System.out.print(" ");
f = 1;
System.out.print(temp);
int t;
for (t = j; t >= h && temp < data[t - h]; t -= h) {
data[t] = data[t - h];
}
data[t] = temp;
}
}
}
System.out.println();
}
}
堆排序
思想可归纳为两个操作:
(1)根据初始数组去构造初始堆(构建一个完全二叉树,保证所有的父结点都比它的孩子结点数值大)。
(2)每次交换第一个和最后一个元素,输出最后一个元素(最大值),然后把剩下元素重新调整为大根堆。
当输出完最后一个元素后,这个数组已经是按照从小到大的顺序排列了。
public class HeapSort {
public static void main(String[] args) {
int n;//元素个数
int[] R; //需排序的数组
Scanner in= new Scanner(System.in);
n=in.nextInt();
R = new int[n];
for(int i=0;i<n;i++){
R[i]=in.nextInt();
}
heapSort(R);
for(int i=0;i<n;i++){
System.out.print(R[i]+" ");
}
System.out.println();
}
static void heapSort(int[] R){
int tmp = 0;
heapAdjust(R,0,R.length-1);//建最小堆
for(int i=0;i<R.length;i++){
System.out.print(R[i]+" ");
}
System.out.println();
for(int i = R.length-1;i>0;--i){ //取出堆顶最大元素。
tmp = R[0];
R[0]=R[i];
R[i]=tmp;
heapAdjust(R,0,i-1);//剩下的元素继续构建最大堆
}
}
static void heapAdjust(int[] R,int low,int high){
if((low<high)&&(high<R.length)){
int j = 0;
int k = 0;
int tmp = 0;
for(int i=(high-1/ 2);i>=low;--i){//根据完全二叉树的特性,用最后的元素求其父亲的地址,若以0作为根:左孩=2*父+1,右孩=2*父+2。若以1为根:左孩=2*父,右孩=2*父+1,现已知儿子求父亲。
tmp = R[i];
k = i;
j = 2 * k + 1 ;//左孩子
while (j <= high) {
if ((j < high) && (j + 1 <= high) && (R[j] < R[j + 1])) {//若右孩子大于左孩子则j++
++j;
}
if (tmp < R[j]) {//若孩子大于父亲则覆盖
R[k] = R[j];
k = j;
j = 2 * k + 1;
} else {
break;
}
}
R[k]=tmp;//填补k对应的位置
}
}
}
}
快速排序
快速排序的基本思想是,通过一轮的排序将序列分割成独立的两部分,其中一部分序列的关键字(这里主要用值来表示)均比另一部分关键字小。继续对长度较短的序列进行同样的分割,最后到达整体有序。在排序过程中,由于已经分开的两部分的元素不需要进行比较,故减少了比较次数,降低了排序时间。详细描述:首先在要排序的序列 a 中选取一个中轴值,而后将序列分成两个部分,其中左边的部分 b 中的元素均小于或者等于 中轴值,右边的部分 c 的元素 均大于或者等于中轴值,而后通过递归调用快速排序的过程分别对两个部分进行排序,最后将两部分产生的结果合并即可得到最后的排序序列。
“基准值”的选择有很多种方法。最简单的是使用第一个记录的关键字值。但是如果输入的数组是正序或者逆序的,就会将所有的记录分到“基准值”的一边。较好的方法是随机选取“基准值”,这样可以减少原始输入对排序造成的影响。但是随机选取“基准值”的开销大。
import java.util.Scanner;
public class QuickSort {
public static void main(String[] args) {
int n;//元素个数
int[] R;//需排序的数组
Scanner in = new Scanner(System.in);
n = in.nextInt();
R = new int[n];
for (int i = 0; i < n; i++) {
R[i] = in.nextInt();
}
quickSort(R, 0, R.length - 1);
for (int i = 0; i < n-1; i++) {
System.out.print(R[i] + " ");
}
System.out.println(R[n-1]);
}
public static int[] quickSort(int[] data, int low, int hight) {
int pivot = data[low];
int i = low + 1;
int j = hight;
int temp;
while (i < j) {
while ((j > i) && pivot <= data[j]) {//若data[j]大于我们所选的基准则j往前走
j--;
}
while ((j > i) && pivot >= data[i]) {//若data[i]小于我们所选的基准则j往后走
i++;
}
if (i < j) {//交换i,j对应的值
temp = data[i];
data[i] = data[j];
data[j] = temp;
}
}
if(data[j]>data[low])//我所选的值比基准值大则基准与前面一个元素交换。
{
j--;
i--;
}
if (data[j] < data[low]) {//与基准交换
temp = data[low];
data[low] = data[j];
data[j] = temp;
}
if (i - low > 1)//分治如上调整
quickSort(data, low, i - 1);
if (hight - j > 1)
quickSort(data, j + 1, hight);
return data;
}
}