Java 排序算法的基本实现

目录

 

1. 排序算法分类

2. 不稳定排序

2.1 插入排序

2.2 快速排序

2.3 堆排序 - 完全二叉树

3. 稳定排序

3.1 冒泡排序

3.2 直接插入排序

3.3 归并排序

总结:


1. 排序算法分类

 

2. 不稳定排序

2.1 插入排序

/**
 * 选择排序
 * 		每一次从待排序的数据元素中选出最小(或最大)的一个元素,
 * 		存放在序列的起始位置,直到全部待排序的数据元素排完。
 * 	时间复杂度:O(n^2) 
 * 	空间复杂度:O(1)
 * @param arr
 */
public void selectSort(int arr[]) {
	for(int i = arr.length-1; i >= 0; i--) {
		int tmp = arr[i];
		int index = i;
		for(int j = 0; j < i; j++) {
			if(arr[j] > tmp) {
				index = j;
				tmp = arr[j];
			}
		}
		arr[index] = arr[i];
		arr[i] = tmp;
	}
}

2.2 快速排序

/**
 * 快速排序:
 * 		通过一趟排序将要排序的数据分割成独立的两部分,
 * 		其中一部分的所有数据都比另外一部分的所有数据都要小,
 * 		然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,
 * 		以此达到整个数据变成有序序列。
 * 
 * 1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
 * 2)以第一个数组元素作为关键数据,赋值给key,即key=A[0]
 * 3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换
 * 4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换
 * 5)重复第3、4步,直到i=j;
 * 		(3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值
 * 		使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。
 * 		另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
 * 
 * 	时间复杂度:
 * 		最好O(nlogn) 
 * 		最坏:O(n^2)
 * 	空间复杂度:O(nlogn)
 * 
 * @param arr
 */
public void fastSort(int arr[], int begin, int end){
	if(begin >= end) {
		return;
	}
	int index = partition(arr, begin, end);
	fastSort(arr, begin, index-1);
	fastSort(arr, index+1, end);
}

private int partition(int arr[], int begin, int end) {
	int tmp = arr[begin];
	while(begin < end) {
		while(begin < end && arr[end] >= tmp) {
			end--;
		}
		arr[begin] = arr[end];
		
		while(begin < end && arr[begin] <= tmp) {
			begin++;
		}
		arr[end] = arr[begin];
	}
	arr[end] = tmp;
	return begin;
}

2.3 堆排序 - 完全二叉树

/**
 * 堆排序
 * 		将二叉树调整为大顶堆,然后将堆的最后一个元素与堆顶元素(即二叉树的根结点)进行交换后,
 * 		堆的最后一个元素即为最大记录;接着将前n-1个元素调整为大顶堆,
 * 		再将堆顶元素与当前堆的最后一个元素进行交换后得到次大的记录
 * 		重复该过程直到调整的堆中只剩一个元素为止,该元素即为最小记录,
 * 		此时可得到一个有序序列
 * 
 * 	时间复杂度:O(nlogn)
 * 	空间复杂度:O(1)
 * 
 * @param arr
 */
public void heapSort(int arr[]) {
	for(int i = arr.length/2-1; i >=0; i--) {
		headAdjust(arr, i, arr.length-1);
	}
	for(int j = arr.length-1; j >= 0; j--) {
		swap(arr, j, 0);
		for(int i = j/2-1; i >=0; i--) {
			headAdjust(arr, i, j-1);
		}
	}
}
private void headAdjust(int arr[], int index,int len) {
	for(int i = index*2+1; i <= len && i<=index*2+2; i++) {
		if(arr[i] > arr[index]) {
			swap(arr, i, index);
		}
	}
}
private void swap(int[] arr, int i, int j) {
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}

3. 稳定排序

3.1 冒泡排序

/**
 *  冒泡排序:
 * 		1. 比较相邻的元素。如果第一个比第二个大,将两个值进行交换。
 * 		2. 对每一对相邻的元素做同样的工作,从开始到第一对到最后一对。
 * 			比较结果是最大的元素在最后一位。
 * 		3. 针对所有的元素重复以上的步骤,除了最后一个。
 * 		针对每次越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
 * 
 * 	最好时间复杂度:O(n)
 * 	最坏时间复杂度:O(n^2)
 * 
 * 	平均时间复杂度:O(n^2)
 * 	空间复杂度:O(1)
 * 
 * @param arr 待排序数组
 */
public void bubbleSort(int arr[]) {
	boolean flag = true; // 记录数组是否已经有序,默认true:无序,false:有序
	for(int i = arr.length-1; i >= 0 && flag; i--) {
		flag = false;
		for(int j = 0; j < i; j++) {
			if(arr[j] > arr[j+1]) {// 数据无序时,进行交换
				int tmp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = tmp;
				flag = true; // 当本次循环有数据交换,代表当前无序
			}
		}
	}
}

3.2 直接插入排序

/**
 *  直接插入排序:
 * 		1. 首先在当前有序区R[1..i-1]中查找R[i]的正确插入位置k(1≤k≤i-1);
 * 		2. 然后将R[k..i-1]中的记录均后移一个位置,腾出k位置上的空间插入R[i]。
 * 	
 * 	时间复杂度:O(n^2)
 * 	空间复杂度:O(1)
 * 	
 * @param arr 待排序数组
 */
public void insertSort(int[] arr) {
	if(arr == null || arr.length <= 1) { // 当数组为空,或者数组长度小于等于1时,不需要排序
		return;
	}
	for(int i = 1; i < arr.length; i++) {
		int tmp = arr[i];
		int j;
		for(j = i; j > 0 && arr[j-1] > tmp; j--) {
			arr[j] = arr[j-1];
		}
		arr[j] = tmp;
	}
}

3.3 归并排序

/**
 *   归并排序:
 * 		将每两个相邻的长度为1的子序列进行归并,得到n/2个长度为2或1的有序子数列,
 * 		再将两两归并,反复执行此过程,直到得到一个有序序列
 * 
 * 	时间复杂度:O(nlogn)
 * 	空间复杂度:O(n)
 * 
 * @param arr 待排序数组
 * @param begin 开始位置
 * @param end 结束位置
 */
public void mergeSort(int arr[], int begin, int end) {
	int mid = (begin + end)/2;
	if(begin < end) {
		mergeSort(arr, begin, mid);
		mergeSort(arr, mid+1, end);
		merge(arr, begin, mid, end);
	}
}
private void merge(int arr[], int begin, int mid, int end) {
	int[] tmp =  new int[end-begin+1];
	int i = begin;
	int j = mid + 1;
	int k = 0;
	while(i <= mid && j <= end) {
		if(arr[i] < arr[j]) {
			tmp[k++] = arr[i++];
		}else {
			tmp[k++] = arr[j++];
		}
	}

	while(i <= mid) {
		tmp[k++] = arr[i++];
	}
	
	while(j <= end) {
		tmp[k++] = arr[j++];
	}
	
	for(int t = 0; t < tmp.length; t++) {
		arr[begin+t] = tmp[t];
	}
}

 

4. 运行结果比较

 

5. 总结

算法是代码的灵魂,而算法的实现只是基础,在此基础上面还要进行算法优化,本次只是算法的实现,算是对排序的复习,并没有进行优化操作。

就像上面的运行结果一样,同等条件下,对各个排序算法各自随机产生一个长度为5000的整型数组,只不过对冒泡进行了一点优化,结果可以看出此时冒泡的性能竟然是最好的,比快速排序还要快两个数量级。

这就是优化的力量,通过优化可以让算法速度有大幅度的提升,才是进步的方向。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值