常见的排序算法

常见的排序算法

冒泡排序

思路:
将当前元素与下一个元素比较,如果大于下一个元素则交换位置。这样最大的元素就会冒泡到最后一位。
对未排序部分重复这个过程。

// 时间复杂度 平均/最坏--O(n2) 最好--O(n)
// 空间复杂度--O(1)
// 稳定:不会交换相等元素的位置
void bubbleSort(int[] arr) {
	int len = arr.length;
	for (int i = 0; i < len - 1; i++) {
		for (int j = 0; j < len - 1 - i; j++) {
			if (arr[j] > arr[j + 1]) {
				int temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
			}
		}
	}
}

快速排序

思路:
以第一个元素为基准pivot,将数组分为两部分,左侧为<=pivot的元素,右侧为>pivot的元素,对两部分递归使用快速排序。
我们选取第一个元素作为基准。排序时先移动右指针,这样可以将需要交换的元素暂时存储在被当做基准的位置。

// 时间复杂度 最坏--O(n2) 平均/最好--O(nlogn)
// 空间复杂度--O(nlogn)
// 不稳定
void sort(int[] arr, int head, int tail) {//初始值为头和尾
	//递归出口
	if(head>=tail) {
		return;
	}
	int pivot=arr[head]; //基准
	int left=head;
	int right=tail;
	
	while(left<right){
		//基准左边元素小于它,右边元素大于它
		while(left<right&&arr[right]>pivot) {//右边元素小于基准停下
			right--;
		}
		arr[left]=arr[right];
		while(left<right&&arr[left]<=pivot) {//左边元素大于基准停下
			left++;
		}
		arr[right]=arr[left];
		//交换左右元素
	}
	//将基准放到中间
	arr[left]=pivot;
	
	sort(arr, head, left-1);
	sort(arr, right+1, tail);	
}

堆排序

思路:
堆是一个近似的完全二叉树,可以用数组存储。对于下标为i的结点,它的左孩子为2i+1,右孩子为2i+2。大顶堆中父节点大于子节点,小顶堆中父节点小于子节点。
我们首先构建一个大顶堆:对于每一个有孩子的结点,比较它与子节点的大小(先左后右),如果小于子节点,则进行交换。从最末一个有孩子的节点开始,直到根节点。
大顶堆的根结点是序列中最大的元素,我们将根节点与最末一个结点进行交换,则交换处前面为堆的无序部分,后面为堆的有序部分。我们对无序部分进行调整。
堆的调整用到了递归,将当前结点与子结点进行比较(先左后右),如果小于子节点则进行交换,然后再将结点值所在位置继续与它的子节点进行比较。递归出口为当前结点没有子节点或者不需要交换。

// 时间复杂度 最坏--O(n2) 平均/最好--O(nlogn)
// 空间复杂度--O(1)
// 不稳定
public class Heap {
	public void buildHeap(int[] arr) { // 构建大顶堆
		int len=arr.length;
		for(int i=len/2-1;i>=0;i--) { // 2i+1<len或2i<len才有子节点
			this.compare(arr, i, len);
		}
	}
	
	public void heapSort(int arr[]) { //堆排序
		this.buildHeap(arr);
		int len=arr.length;
		int templen=len;
		for(int i=len-1;i>0;i--) { // 将根结点与无序部分的最后一个结点交换位置,然后调整新的无序堆
			this.exchange(arr, 0, i);
			templen--;
			this.compare(arr, 0, templen);
		}
	}
	
	public void exchange(int arr[], int i, int j) { //交换arr[i]与arr[j]
		int temp=arr[i];
		arr[i]=arr[j];
		arr[j]=temp;
	}
	
	public void compare(int arr[], int i, int len) { //父节点小于子节点,交换,右孩子大于左孩子(先左后右)
		int left=2*i+1;
		int right=2*i+2;
		int flag=0;
		if(left<len&&arr[i]<arr[left]) { // left
			this.exchange(arr, i, left);
			flag=left;
		}
		if(right<len&&arr[i]<arr[right]) { // right
			this.exchange(arr, i, right);
			flag=right;
		}
		if(flag!=0) {
			compare(arr, flag, len);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值