排序与二分查找

比较类排序:

平均时间复杂度,最坏时间复杂度,最好时间复杂度。
稳定性:是否改变相对位置。针对a==b,本来a在b前,不稳定可能排序后a在b后。

1. 冒泡排序:

每次两两交换将较大(较小)放后面。
平均O(n2),最坏O(n2),最好(已排序好)O(n)。稳定

void bubblesort(vector<int> &nums){
	for(int i=0;i<nums.size();++i){
		for(int j=0;j<nums.size()-i-1;++j){
			if(nums[j]>nums[j+1])
				swap(nums[j],nums[j+1]);
		}
	}
}
2. 选择排序

每次选择最大(最小)值放至最后(最前).
平均O(n2),最坏O(n2),最好O(n2)。不稳定

void selectionsort(vector<int> &nums){
	for(int i=0;i<nums.size();++i){
		int maxn=0;
		for(int j=0;j<nums.size()-i;++j){
			if(nums[j]>nums[maxn]){
				maxn=j;
			}
		}
		swap(nums[maxn],nums[nums.size()-i-1]);
	}
}
3. 插入排序

将未排序部分首位从后向前搜索插入已排序部分
平均O(n2),最坏O(n2),最好O(n)。稳定

void insertionsort(vector<int> &nums){
	for(int i=0;i<nums.size();++i){
		int tmp=nums[i],idx=i-1;
		while( idx>=0 && tmp<nums[idx]) {
			nums[idx+1]=nums[idx];
			idx--;
		}
		nums[idx+1]=tmp;
	}
}
4. 希尔排序

插入排序的改进版。将待排序数组分为若干步长的子数组,对子数组进行插入排序。
平均O(n1.3),最坏O(n2),最好O(n)。不稳定:由于不同子数组的插入排序,导致之间稳定性破坏。

void shellsort(vector<int> &nums){
	for(int gap=nums.size()/2;gap>0;gap/=2){
		for(int i=0;i<nums.size();++i){
			int tmp=nums[i],idx=i-gap;
			while( idx>=0 && nums[idx]>tmp){
				nums[idx+gap]=nums[idx];
				idx-=gap;
			}
			nums[idx+gap]=tmp;
		}
	}
}
5. 归并排序

分治法。 对每个子序列排序,合并子序列。
分治法:平均O(nlogn),最坏O(nlogn),最好O(nlogn)。稳定。
空间复杂度O(n)。空间换时间。

vector<int> merge(vector<int> l, vector<int> r) {
	vector<int> result;
	while (l.size() > 0 && r.size() > 0) {
		if (l[0] < r[0]) {
			result.push_back(l[0]);
			l.erase(l.begin());
		}
		else {
			result.push_back(r[0]);
			r.erase(r.begin());
		}
	}
	if (l.size() > 0) result.insert(result.end(), l.begin(), l.end());
	else result.insert(result.end(), r.begin(), r.end());
	return result;
}
vector<int> mergesort(vector<int> &nums) {
	int len = nums.size();
	if (len < 2) return nums;
	int mid = len / 2;
	vector<int> left = vector<int>(nums.begin(), nums.begin()+mid);
	vector<int> right = vector<int>(nums.begin()+mid, nums.end());
	return merge(mergesort(left), mergesort(right));
}
6. 快速排序

分治法。选择基准将其调整至正确位置,然后分别对左右递归排序。
平均O(nlogn),最坏O(n2),最好O(nlogn)。不稳定.
空间O(nlogn)

int partition(vector<int> &nums,int left,int right){
	int pivot=left,index=left+1;
	for(int i=left+1;i<=right;++i){
		if(nums[i]<nums[pivot]){
			swap(nums[i],nums[index++]);
		}
	}
	swap(nums[pivot],nums[index-1]);
	return index-1;
}
// or
int partition(vector<int> &nums,int left,int right){
	int pivot=nums[left];
	while(left<right){
		while(left<right&&nums[right]>=pivot) right--;
		if(left<right) nums[left++]=nums[right];
		while(left<right&&nums[left]<=pivot) left++;
		if(left<right) nums[right--]=nums[left];
	}
	nums[left]=pivot;
	return left;
}
void quicksort(vector<int> &nums,int left,int right){
	if(left<right){
		int mid=partition(nums,left,right);
		quicksort(nums,left,mid-1);
		quicksort(nums,mid+1,right);
	}
}
7. 堆排序

使用堆节点保存数据以完成排序。堆是近似完全二叉树的结构,满足子节点的数值小于(大于)父节点。
大顶堆:父节点值大于等于子节点值,用于升序排列(用于易取最大值放最后)
小顶堆:父节点值小于等于子节点值,用于降序排列
平均O(nlogn),最坏O(nlogn),最好O(nlogn)。不稳定.
空间O(1)。

// 调整最大堆
void  max_heapify(vector<int> &nums,int start,int end){
	int dad=start;
	int son=dad*2+1;//左子节点
	while(son<=end){
		if(son+1<=end&&nums[son]<nums[son+1])
			son++;// 先比较两个子节点选择最大的
		if(nums[son]<nums[dad]) return;// 如果子节点都比父节点小,无需调整,退出循环
		else{// 否则交换父子节点。此时原本父节点调整为子节点可能影响子节点所在子树的结构,重新调整子节点子树(将子节点作为新的父节点)。
			swap(nums[son],nums[dad]);
			dad=son;
			son=dad*2+1;
		}
	}
}
void heapsort(vector<int> &nums,int len){
	// 将原数组构建为大顶堆
	for(int i=len/2-1;i>=0;--i)
		// 从最后一个非叶子节点调整结构
		max_heapify(nums,i,len-1);
	// 交换堆顶与末尾元素+调整剩余区间堆结构 
	for(int i=len-1;i>0;--i){
		swap(nums[0],nums[i]);
		max_heapify(nums,0,i-1);// 因为与头结点交换了位置,所以改变了头结点所在子树的结构
	}	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值