快速排序,归并排序,二分查找

排序的稳定性:

如果在排序当中,数组中有两个值是相等的,但是排完序这两个数的先后位置发生改变,那就是不稳定的,如果这两个相等的数在排完序后位置是没有改变的,我们就认为这个排序是稳定的。
归并排序是稳定的
快排编程稳定的方法很简单,就是想一个机制,让这些比较的东西里面没有重复的(可以把数值比较转换为pair比较<nums, index>,就是转换成比较一个对儿里面的数值和下标完全相同时才算相等的值(显然此时数组中绝对没有重复的相等的对儿)

快速排序 时间复杂度:平均是o(nlogn) 最差是n平方

算法思想:分治法

算法主体思路:

  1. 确定分界点

把这个给定的数组,用数组中的一个数x来分成左右两个部分,满足:左边的部分要小于等于x,右边的部分要大于等于x

  1. 分出左右两个部分
    然后将分出来的左右部分继续递归(先分出来两边,再分别递归两边)

  2. 再分别对左右两个部分继续分下去,递归

void quick_sort(int q[], int l, int r) {
	if(l>=r) return;
	int x = q[(l+r)>>1], i = l-1, j = r + 1;
	//划分区间为两个部分,左部分小于等于x,右部分大于等于x
	while(i < j) {
		do i++; while(q[i] < x);
		do j--; while(q[j] > x);
		if(i < j) swap(q[i], q[j]);
	}
	quick_sort(q, l, j);//注意边界问题,这里选择j的时候,边界不能选择r;选择i-1的时候,边界不能选择l
	//否则会因为[1,2]这个样例陷入死循环中,因此此时的中间位置表示为(l+r+1)>>2
	quick_sort(q, j+1, r);
}

归并排序

算法主体思路:

  1. 确定分界点
    mid = (l+r)/2
  2. 左右两边排序,合并

递归:先递归两边,再去对两个区间合并,合二为一!

Const int N = 1e6 + 10;
int q[N], temp[N];
void merge_sort(int q[], int l, int r) {
	if(l >= r) return;
	int mid =  (l + r) >> 1;
	merge_sort(q, l, mid), merge_sort(q, mid+1, r);
	int i = l, j = mid + 1, k = 0;
	while( i <= mid && j <= r) {
	if(q[i] < q [j]) temp[k++] = q[i++];
	else temp[k++] = q[j++];
	}
	while( i<= mid) temp[k++] = q[i++];
	while( j<= r) temp[k++] = q[j++];
	for( i = l, j = 0; i <= r; i++, j++) q[i] = temp[j];
}

二分查找

算法主体思路

我们定义的性质一定是有边界的,我们的二分一定可以把这个边界给分出来。 使用二分可以去找这个性质的边界,即能找到左边界,又能找到右边界;
整数二分:
二分的时候一定要想一个性质把整个区间一分为二,可以画一个线段图用来抠边界问题,注意在二分的时候一定要保证我们的答案是在重新分好的区间里面的。
模板1:
确定mid
写check函数
如果q[mid]满足check函数,则更新 r = mid; 否则 l = mid + 1;
模板2:
确定mid
写check函数
如果q[mid]满足check函数,则更新 l = mid;否则r = mid - 1;

我们用一道题来验证:
求数组中的数的范围
求数组中数的范围

#include <iostream>
using namespace std;
const int N  = 100010;
int n, m;
int q[N];
int main() {
	scanf("%d%d", &n, &m);
	for(int i = 0; i < n; i++) {
		scanf("%d",&q[i]);
		}
	while(m--) {
		int x;
		scanf("%d", &x);
		int l = 0, r = n - 1;
		while(l < r) {
		//模板1:我们定义右半边是大于等于x的,左半边是小于x的。check函数检查
			int mid = (l + r) >> 1;
			if(q[mid] >= x) r = mid;//检查mid位置的数是否满足大于等于x,这样的话我们就可以x的左边界			
			else l = mid - 1;
		}
		if(q[i] != x) cout << "-1 -1" << endl;
		else {
			cout << l << " ";
			int l = 0, r = n - 1;
			while(l < r) {
				int mid = (l + r + 1) >> 1;
				if(q[mid] <= x) l = mid;
				else r = mid - 1;
			}
			cout << l << endl;
		}
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值