七大排序实现

一、插入排序(稳定的)

代码:

//插入排序(稳定的)
	/*
	 * 其实现思路是:序列前几个元素已经有序后,将后面的元素遍历插入到前面的序列中
	 * 时间复杂度是:O(n2)
	 * */
	public static void insertSort(int a[]) {
		for(int i = 2 ; i <= a.length - 1 ; i ++) {  //第一个元素不用插入 , 所以操作元素是2 ~ n
			if(a[i] < a[i - 1]) {
				a[0] = a[i];
				int j;
				for(j = i - 1 ; a[0] < a[j] ; j --) a[j + 1] = a[j]; //后移操作
				a[j + 1] = a[0]; //j+1 是因为前一个循环后j在插入位置的前面一个位置
			}
		}
	}

折半插入排序

代码:

public static void binary_insertSort(int a[]) {
		for(int i = 2 ; i < a.length ; i ++) {
			if(a[i] < a[i - 1]) {
				a[0] = a[i];
				int low = 1;
				int high = i - 1;
				while(low <= high) {
					int mid  = (low + high) / 2;
					if(a[0] > a[mid]) low = mid + 1;
					else high = mid - 1;
				}
				int j;
				for(j = i - 1;  j >= high + 1; j --) {
					a[j + 1] = a[j];
				}
				a[j + 1] = a[0]; 
			}
		}
	}

问题:①为什么最后j选取和high+1进行比较?

       这是由二分所决定的,在二分结束时high指向最大的小于a[0]的元素,low指向最小的大于a[0]的元素,且low = high + 1;所以对于插入位置需要将从 high + 1 ~ i - 1的元素进行后移。

二、希尔排序(不稳定的)

希尔排序是在插入排序的基础上实现的。

代码:

public static void shell(int a[]) {
		int n = a.length;
		for(int gap = n / 2 ; gap > 0 ; gap /= 2) { //确定步长因子序列,每次都是减半
			for(int i = gap ; i < n ; i ++) { 
				int temp = a[i];
				int j;
				for(j = i ; j >= gap && a[j - gap] > temp ; j -= gap) { //对每一个步长组进行插入排序
					a[j] = a[j - gap];
				}
				a[j] = temp; 
			}
		}
	}

解释:首先通过一个for循环来生成步长因子序列,然后对于每一个步长因子,对于确定出来的分组进行插入排序。

对比希尔排序中插入排序和普通插入排序的区别:

①普通插入排序中最后插入元素需要索引+1,因为循环的最后j更新的位置是插入位置的前一个位置,而希尔排序中由于更新后j就是指的是插入位置。

三、冒泡排序(稳定的)

代码:

public static void bubble_sort(int a[]){
		for(int i = 1 ; i <= a.length - 1 ; i ++) { //此处a.length = n + 1
			int flag = 0;
			for(int j = 1 ; j <= a.length - 1 - i ; j ++) {
				if(a[j] > a[j + 1]) {
					a[0] = a[j];
					a[j] = a[j + 1];
					a[j + 1] = a[0];
					flag = 1;
				}
			}
			if(flag == 0) break; //当整个过程中没有交换操作则是有序的
		}
	}

四、快速排序(不稳定的)

代码:

public static void quick_sort(int a[] , int l , int r) {
		if(l >= r) return;
		int x = a[(l + r) / 2] , i = l - 1 , j = r + 1;
		while(i < j) {
			do i ++; while(a[i] < x);
			do j -- ; while(a[j] > x);
			if(i < j) {
				int temp = a[i];
				a[i] = a[j];
				a[j] = temp;
			}
		}
		quick_sort(a , l , j);
		quick_sort(a , j + 1, r);
	}

五、归并排序

代码:

public static void merge_sort(int a[] , int l , int r , int temp[]) {
		if(l >= r) return;
		int mid = (l + r) / 2 , i = l , j = mid + 1 , k = 0;
		merge_sort(a , l , mid , temp);
		merge_sort(a , mid + 1 , r , temp);
		while(i <= mid && j <= r) {
			if(a[i] < a[j]) temp[k ++] = a[i ++];
			else temp[k ++] =  a[j ++];
		}
		while(i <= mid) temp[k ++] = a[i ++];
		while(j <= r) temp[k ++] = a[j ++];
		
		for(i = l , j = 0 ; i <= r ; i ++ , j ++) a[i] = temp[j];
	}

·六、选择排序

代码:

public static void select_sort(int a[]) {
		for(int i = 1 ; i < a.length - 1 ; i ++) { //只用循环n - 1次因为最后第n次已经是有序的
			int k = i;
			for(int j = i + 1 ; j <= a.length - 1; j ++) {
				if(a[j] < a[k]) k = j;  //找到目前最小的位置
			}
			if(i != k) {
				a[0] = a[i];
				a[i] = a[k];
				a[k] = a[0];
			}
		}
	}

七、堆排序

代码:

//堆排序
	public static void heapsort(int a[]) {
		//先建堆(从顶到底建堆)
		for(int i = 0 ; i < a.length ; i ++) {
			heapInsert(a , i);
		}
		//进行堆排序:由于是大顶堆,所以每次将堆顶与最后结点交换,然后将堆顶下沉
		int size = a.length;
		while(size > 1) {
			swap(a , 0  , --size);
			heapify(a , 0 , size);
		}
	}
	
	//堆排序的优化
	public static void heapsort2(int a[]) {
		int size = a.length;
		for(int i = a.length - 1 ; i >= 0 ; i --) {
			heapify(a , i , size);
		}
		while(size > 1) {
			swap(a , 0 , --size);
			heapify(a , 0 , size);
		}
		
	}
	
	//堆上调函数
	public static void heapInsert(int a[] , int i) {
		//对于堆的一个结点i其父节点是(i - 1)/ 2 , 当索引从0开始时。
		while(a[i] > a[(i - 1) / 2]) {
			swap(a , i , (i - 1) / 2);
			i = (i - 1) / 2;//更新位置,确保能够找到最终的位置
		}
	}
	
	//堆下调函数
	public static void heapify(int a[] , int i , int size) {
		int l = 2 * i + 1; //先找到左节点
		while(l < size) { //边界是size
			int best = l + 1 < size && a[l + 1] > a[l] ? l + 1 : l; //找到两个结点中最大的一个
			best = a[best] > a[i] ? best : i; //比较子节点和当前结点哪一个更大并更新
			if(best == i) {
				break;
			}
			swap(a , best , i); //当子节点更大时调整位置
			i = best; //更新位置
			l = 2 * i + 1;
		}
	}
	
	//堆排序中交换函数
	public static void swap(int a[] , int i , int j) {
		int temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}

八、主方法测试输出

public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Scanner scan = new Scanner(System.in);
		int n = scan.nextInt();
		int a[] = new int[n + 1];
		System.out.println("(输入序列):");
		for(int i = 1 ; i <= n ; i ++) {
			a[i] =  scan.nextInt();
		}
		//插入排序
		int temp[] = a.clone();
		System.out.println("插入排序的结果:");
		insertSort(temp);
		for(int i = 1 ; i <= n ; i ++) {
			System.out.print(temp[i] + " ");
		}
		System.out.println();
		
		//插入排序优化折半插入排序
		int temp1[] = a.clone();
		System.out.println("折半插入排序的结果:");
		binary_insertSort(temp1);
		for(int i = 1 ; i <= n ; i ++) {
			System.out.print(temp1[i] + " ");
		}
		System.out.println();
		
		//希尔排序
		int temp2[] = a.clone();
		System.out.println("希尔排序的结果:");
		shell(temp2);
		for(int i = 1 ; i <= n ; i ++) {
			System.out.print(temp2[i] + " ");
		}
		System.out.println();
		
		
		//快速排序
		int temp3[] = a.clone();
		System.out.println("快速排序的结果:");
		quick_sort(temp3 , 1 , n);
		for(int i = 1 ; i <= n ; i ++) {
			System.out.print(temp3[i] + " ");
		}
		System.out.println();
		
		//归并排序
		int temp4[] = a.clone();
		System.out.println("归并排序的结果:");
		int tmp[] = new int[n + 1];
		merge_sort(temp4 , 1 , n , tmp);
		for(int i = 1 ; i <= n ; i ++) {
			System.out.print(temp4[i] + " ");
		}
		System.out.println();
		
		//冒泡排序
		int temp5[] = a.clone();
		System.out.println("冒泡排序的结果:");
		bubble_sort(temp5);
		for(int i = 1 ; i <= n ; i ++) {
			System.out.print(temp5[i] + " ");
		}
		System.out.println();
		
		
		//选择排序
		int temp6[] = a.clone();
		System.out.println("选择排序的结果:");
		select_sort(temp6);
		for(int i = 1 ; i <= n ; i ++) {
			System.out.print(temp6[i] + " ");
		}
		System.out.println();
		
		//堆排序(为处理索引问题,这里重新进行一下输入操作)
		System.out.println("新输入一个序列用于堆排序:");
		int b[] = new int[n];
		for(int i = 0 ; i < n ; i ++) {
			b[i] = scan.nextInt();
		}
		System.out.println("堆排序的结果:");
		heapsort2(b);
		for(int i = 0 ; i < n ; i ++) {
			System.out.print(b[i] + " ");
		}
		System.out.println();
	}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值