排序(java)

本文介绍了四种常见的排序算法:归并排序、希尔排序、堆排序和快速排序。详细讲解了每种算法的工作原理,并提供了Java实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

归并排序

概括为一句话:将整体分为两个部分分别排序,然后择优(依次选择较小的插入或较大的)合并新的有序整体。这个过程本身就是递归,当只剩下一个元素的时候也就相当于排好序了。

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;
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值