八大排序算法详解(java版)

1.冒泡排序
//冒泡排序
	//冒泡排序就是每次选择一个最大值放到后面
	public void bubbleSort(int[] arr) {
		//外层循环控制需要比较的次数   一共是n-1次
		for(int i=0; i<arr.length-1; i++) {
			//内层循环进行冒泡,因为每完成一次外层循环,就会在后面多一个有序序列,因此可以不用比较		
			for(int j=0; j<arr.length-i-1; j++) {
				if(arr[j]>arr[j+1]) {
					int temp = arr[j];
					arr[j] = arr[j+1];
					arr[j+1] = temp;
				}
			}
		}
	}
2.选择排序
//选择排序
	//选择排序就是依次选择最小值放在最前面
	public void selectSort(int[] arr) {
		//外层循环控制每次选择的位置
		for(int i=0; i<arr.length-1; i++) {
			int min = i;
			//内层循环表示第i个位置依次和后面的元素比较选出最小的值,并放在第i个位置
			for(int j=i+1; j<arr.length; j++) {
				if(arr[j]<arr[min]) {
					min = j;
				}
			}
			//把选出的最小值放在第i个位置	
			if(min!=i) {
				int temp = arr[i];
				arr[i] = arr[min];
				arr[min] = temp;
			}
		}
	}
3.直接插入排序
//直接插入排序
	public void insertSort(int[] arr) {
		int temp,j;
		for(int i=1; i<arr.length; i++) {
			temp = arr[i];
			j = i-1;
			while(j>=0&&temp<arr[j]) {
				arr[j] = arr[j-1];
				j--;
			}
			arr[j+1] = temp;
		}
	}
4.希尔排序
//希尔排序 使用移动元素法
//希尔排序就是插入排序的升级版,只不过步长不再是1
public void shellSort1(int[] arr){
	int length = arr.length;
	//先分组,直到gap等于1
	for(int gap=length/2; gap>0; gap/=2) {
		//分成了gap组之后,从第gap个元素开始进行插入排序
		for(int j=gap; j<length; j++) {
			if(arr[j]<arr[j-gap]) {
				int k = j;
				int temp = arr[j];
				while(k-gap>=0&&temp<arr[k-gap]) {
					arr[k] = arr[k-gap];
					k-=gap;
				}
				arr[k] = temp;
			}
		}
	}
}

//希尔排序 使用交换元素法 (类似冒泡法)
public void shellSort2(int[] arr){
	int length = arr.length;
	for(int gap=length/2; gap>0; gap/=2) {
		for(int j=gap; j<length; j++) {
			if(arr[j]<arr[j-gap]) {
				int k = j;
				while(k-gap>=0&&arr[k]<arr[k-gap]) {
					int temp = arr[k];
					arr[k] = arr[k-gap];
					arr[k-gap] = temp;
				}
			}
		}
	}
}
5.快速排序(双指针)
//快速排序
public void quickSort(int[] arr,int left,int right) {
	
	//如果没有元素或只有一个元素直接返回,因为一个元素已经有序,无需排序
	if(left>=right)
		return;
	
	//第一个指针指向数组的第一个元素
	int start = left;
	//第二个指针指向数组的最后一个元素
	int end = right;
	
	//缓存直接选择的基准,大部分都是以第一个元素为基准
	int temp = arr[start];
	while(start<end) {
		//从第二个指针开始找到第一个小于基准数的索引,
		//因为循环退出的条件就是arr[end]<temp
		while(start<end&&arr[end]>=temp)
			end--;
		//把找到的小于基准的数放在基准数的左边
		if(start<end)
			arr[start++] = arr[end];
		
		//从第一个指针开始找第一个大于基准数的索引
		while(start<end&&arr[start]<temp)
			start++;
		//把找到的大于基准的数放在基准数的右边
		if(start<end)
			arr[end--] = arr[start];
	}
	//把基准数放在中间,循环结束之后,基准数左边都比基准数小,基准数右边都比基准数大
	arr[start] = temp;
	
	//基准数左边进行快速排序
	quickSort(arr, left, start-1);
	//基准数右边进行快速排序
	quickSort(arr, start+1, right);
}
6.归并排序
//归并排序
public void mergeSort(int[] arr,int left,int right) {
	if(left>=right)
		return;
	int mid = left+(right-left)/2;
	mergeSort(arr, left, mid);
	mergeSort(arr, mid+1, right);
	merge(arr,left,mid,right);
}

//合并两个数组
public void merge(int[] arr,int left,int mid,int right) {
	int t1 = left;
	int t2 = mid+1;
	int k = 0;
	int[] temp = new int[right-left+1];
	while(t1<=mid&&t2<=right) {
		if(arr[t1]<arr[t2])
			temp[k++] = arr[t1++];
		else
			temp[k++] = arr[t2++];
	}
	while(t1<=mid)
		temp[k++] = arr[t1++];
	while(t2<=right)
		temp[k++] = arr[t2++];
	
	for(int i=0; i<k; i++) {
		arr[left++] = temp[i];
	}
}
7.基数排序
//基数排序
public void baseSort(int[] arr) {
	int[][] bucket = new int[10][arr.length];
	int[] bucketCounts = new int[10];
	
	int max = arr[0];
	for(int i=0; i<arr.length; i++)
		if(arr[i]>max)
			max = arr[i];
	int maxLength = (max+"").length();
	int n = 1; 
	for(int i=1; i<=maxLength; i++) {				
		for(int j=0; j<arr.length; j++) {
			int temp = (arr[j]/n)%10;
			bucket[temp][bucketCounts[temp]] = arr[j];  
			bucketCounts[temp]++;
		}
		int index = 0;
		for(int j=0; j<bucketCounts.length; j++) {
			int count = bucketCounts[j];
			for(int k=0; k<count; k++) {
				arr[index++] = bucket[j][k];
			}
			bucketCounts[j] = 0;
		}
		n*=10;
	}
}
8.堆排序
//堆排序    史上最难理解的排序之一
public void heapSort(int[] arr) {
	
	//构建大顶堆 i表示需要调整的每个双亲节点
	for(int i=(arr.length-1-1)/2; i>=0; i--) {
		
		adjustHeap(arr, i, arr.length);
	}
	
	//构建好大顶堆之后,交换堆顶和对底元素并调整堆的结构
	for(int i=arr.length-1; i>0; i--) {
		int temp = arr[i];
		arr[i] = arr[0];
		arr[0] = temp;
		adjustHeap(arr, 0, i);
	}
}
//调整堆的结构
public void adjustHeap(int[] arr,int parent,int length) {
	int temp = arr[parent];
	
	//找到其左孩子
	int lchild = 2*parent+1;
	while(lchild<length) {
		int rchild = lchild+1;
		if(rchild<length&&arr[rchild]>arr[lchild])
			lchild++;
		if(temp>=arr[lchild])
			break;
		arr[parent] = arr[lchild];
		parent = lchild;
		lchild = 2*lchild+1;
	}
	arr[parent] = temp;
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
选择排序算法准则: 每种排序算法都各有优缺点。因此,在实用时需根据不同情况适当选用,甚至可以将多种方法结合起来使用。 选择排序算法的依据 影响排序的因素有很多,平均时间复杂度低的算法并不一定就是最优的。相反,有时平均时间复杂度高的算法可能更适合某些特殊情况。同时,选择算法时还得考虑它的可读性,以利于软件的维护。一般而言,需要考虑的因素有以下四点: 1.待排序的记录数目n的大小; 2.记录本身数据量的大小,也就是记录中除关键字外的其他信息量的大小; 3.关键字的结构及其分布情况; 4.对排序稳定性的要求。 设待排序元素的个数为n. 1)当n较大,则应采用时间复杂度为O(nlog2n)的排序方法快速排序、堆排序或归并排序序。 快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短; 堆排序 : 如果内存空间允许且要求稳定性的, 归并排序:它有一定数量的数据移动,所以我们可能过与插入排序组合,先获得一定长度的序列,然后再合并,在效率上将有所提高。 2) 当n较大,内存空间允许,且要求稳定性 =》归并排序 3)当n较小,可采用直接插入或直接选择排序。 直接插入排序:当元素分布有序,直接插入排序将大大减少比较次数和移动记录的次数。 直接选择排序 :元素分布有序,如果不要求稳定性,选择直接选择排序 5)一般不使用或不直接使用传统的冒泡排序。 6)基数排序 它是一种稳定的排序算法,但有一定的局限性:   1、关键字可分解。   2、记录的关键字位数较少,如果密集更好   3、如果是数字时,最好是无符号的,否则将增加相应的映射复杂度,可先将其正负分开排序

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

华达州

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值