希尔、快排、堆排、归并排序的实现以各复杂度

常见排序算法复杂度

排序方法平均情况最好情况最坏情况辅助空间稳定性
冒泡排序O(n2)O(n)O(n2)O(1)稳定
简单选择排序O(n2)O(n2)O(n2)O(1)不稳定
直接插入排序O(n2)O(n)O(n2)O(1)稳定
希尔排序O(nlogn)~O(n2)O(n1.3)O(n2)O(1)不稳定
堆排序O(nlogn)O(nlogn)O(nlogn)O(1)不稳定
归并排序O(nlogn)O(nlogn)O(nlogn)O(n)稳定
快速排序O(nlogn)O(nlogn)O(n2)O(logn)~O(n)不稳定

算法的稳定性

有一点我们很容易忽略的是排序算法的稳定性。
  排序算法稳定性的简单形式化定义为:如果Ai = Aj,排序前Ai在Aj之前,排序后Ai还在Aj之前,则称这种排序算法是稳定的。通俗地讲就是保证排序前后两个相等的数的相对顺序不变。
  对于不稳定的排序算法,只要举出一个实例,即可说明它的不稳定性;而对于稳定的排序算法,必须对算法进行分析从而得到稳定的特性。需要注意的是,排序算法是否为稳定的是由具体算法决定的,不稳定的算法在某种条件下可以变为稳定的算法,而稳定的算法在某种条件下也可以变为不稳定的算法。
  例如,对于冒泡排序,原本是稳定的排序算法,如果将记录交换的条件改成A[i] >= A[i + 1],则两个相等的记录就会交换位置,从而变成不稳定的排序算法。
  其次,说一下排序算法稳定性的好处。排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,前一个键排序的结果可以为后一个键排序所用。基数排序就是这样,先按低位排序,逐次按高位排序,低位排序后元素的顺序在高位也相同时是不会改变的

希尔排序

void shellSort(vector<int> &nums){
	int gap=0;
	int i=0,j=0;
	for(gap=nums.size()/2;gap>=1;gap/=2){
		for(i=gap;i<nums.size();i++){
			for(j=i-gap;j>=0&&nums[j+gap]<nums[j];j=j-gap)
				swap(nums[j+gap],nums[j]);
		}
	}
}

归并排序

//迭代版
int min(int x, int y) {
    return x < y ? x : y;
}
void merge_sort1(vector<int> &nums){
	vector<int> a=nums;
	vector<int> b(nums.size(),0);
	int seg,start;
	for(seg=1;seg<nums.size();seg+=seg){
		for(start=0;start<nums.size();start+=seg+seg){
			int low=start,mid=min(start+seg,nums.size());
			int high=min(start+seg+seg,nums.size());
			int k=low;
			int start1=low,end1=mid;
			int start2=mid,end2=high;
			while(start1<end1&&start2<end2)
				b[k++]=a[start1]<a[start2]?a[start1++]:a[start2++];
			while(start1<end1)
				b[k++]=a[start1++];
			while(start2<end2)
				b[k++]=a[start2++];
		}
		vector<int> temp=a;
		a=b;
		b=temp;
	}
	nums=a;
}

//递归版
void merge_sort2(vector <int> &nums,vector <int>& temp,int start,int end){
	if(start>=end) return;

	int len=end-start,mid=(len>>1)+start;
	int start1=start,end1=mid;
	int start2=mid+1,end2=end;

	merge_sort2(nums,temp,start1,end1);
	merge_sort2(nums,temp,start2,end2);

	int k=start;
	while(start1<=end1&&start2<=end2)
		temp[k++] = nums[start1] < nums[start2] ? nums[start1++] : nums[start2++];
	while(start1<=end1)
		temp[k++]=nums[start1++];
	while(start2<=end2)
		temp[k++]=nums[start2++];

	nums=temp;
}

快速排序

int partition(vector<int> &nums,int left,int right){
	int i=left,j=right;
	int temp=nums[left];
	while(i<j){
		while(nums[i]<=temp&&i<=j)
			i++;
		while(nums[j]>=temp&&i<=j)
			j--;
		if(i<j)
			swap(nums[i],nums[j]);
	}
	nums[left]=nums[i-1];
	nums[i-1]=temp;
	return i-1;
}


void quick_sort(vector<int> &nums,int left,int right){
	if(left<right){
		int i=partition(nums,left,right);
		quick_sort(nums,left,i-1);
		quick_sort(nums, i+1,right);
	}
}

堆排序

void adjust(vector<int>& nums,int len,int index){
	int left=2*index+1;   //左子节点
	int right=2*index+2;   //右子节点

	int maxIndex=index;

	if(left<len && nums[left]>nums[maxIndex]) maxIndex=left;
	if(right<len && nums[right]>nums[maxIndex]) maxIndex=right;

	if(maxIndex!=index){
		swap(nums[maxIndex],nums[index]);
		adjust(nums,len,maxIndex);
	}
}
void heapSort(vector<int> &nums){

	//构建大根堆
	for(int i=nums.size()/2-1;i>=0;i--){
		adjust(nums,nums.size(),i);
	}

	//调制小根堆
	for(int i=nums.size()-1;i>=1;i--){
		swap(nums[0],nums[i]);//把当其最大的放置到数组末尾
		adjust(nums,i,0);
	}
}

完整代码

#include<iostream>
#include<vector>
using namespace std;


void show(vector<int> nums){
	if(nums.size()==0) return;
	for(int i=0;i<nums.size();i++){
		cout<<nums[i]<<" ";
	}
	cout<<endl;
}


void shellSort(vector<int> &nums){
	int gap=0;
	int i=0,j=0;
	for(gap=nums.size()/2;gap>=1;gap/=2){
		for(i=gap;i<nums.size();i++){
			for(j=i-gap;j>=0&&nums[j+gap]<nums[j];j=j-gap)
				swap(nums[j+gap],nums[j]);

		}
	}
}

int min(int x, int y) {
    return x < y ? x : y;
}


void merge_sort1(vector<int> &nums){
	vector<int> a=nums;
	vector<int> b(nums.size(),0);
	int seg,start;
	for(seg=1;seg<nums.size();seg+=seg){
		for(start=0;start<nums.size();start+=seg+seg){
			int low=start,mid=min(start+seg,nums.size());
			int high=min(start+seg+seg,nums.size());
			int k=low;
			int start1=low,end1=mid;
			int start2=mid,end2=high;
			while(start1<end1&&start2<end2)
				b[k++]=a[start1]<a[start2]?a[start1++]:a[start2++];
			while(start1<end1)
				b[k++]=a[start1++];
			while(start2<end2)
				b[k++]=a[start2++];
		}
		vector<int> temp=a;
		a=b;
		b=temp;
	}
	nums=a;
}



void merge_sort2(vector <int> &nums,vector <int>& temp,int start,int end){
	if(start>=end) return;

	int len=end-start,mid=(len>>1)+start;
	int start1=start,end1=mid;
	int start2=mid+1,end2=end;

	merge_sort2(nums,temp,start1,end1);
	merge_sort2(nums,temp,start2,end2);

	int k=start;
	while(start1<=end1&&start2<=end2)
		temp[k++] = nums[start1] < nums[start2] ? nums[start1++] : nums[start2++];
	while(start1<=end1)
		temp[k++]=nums[start1++];
	while(start2<=end2)
		temp[k++]=nums[start2++];

	nums=temp;

}

int partition(vector<int> &nums,int left,int right){
	int i=left,j=right;
	int temp=nums[left];
	while(i<j){
		while(nums[i]<=temp&&i<=j)
			i++;
		while(nums[j]>=temp&&i<=j)
			j--;
		if(i<j)
			swap(nums[i],nums[j]);
	}
	nums[left]=nums[i-1];
	nums[i-1]=temp;
	return i-1;
}


void quick_sort(vector<int> &nums,int left,int right){
	if(left<right){
		int i=partition(nums,left,right);
		quick_sort(nums,left,i-1);
		quick_sort(nums, i+1,right);
	}
}


//堆排序
//构建大根堆
void adjust(vector<int>& nums,int len,int index){
	int left=2*index+1;   //左子节点
	int right=2*index+2;   //右子节点

	int maxIndex=index;

	if(left<len && nums[left]>nums[maxIndex]) maxIndex=left;
	if(right<len && nums[right]>nums[maxIndex]) maxIndex=right;

	if(maxIndex!=index){
		swap(nums[maxIndex],nums[index]);
		adjust(nums,len,maxIndex);
	}
}

void heapSort(vector<int> &nums){

	//构建大根堆
	for(int i=nums.size()/2-1;i>=0;i--){
		adjust(nums,nums.size(),i);
	}

	//调制小根堆
	for(int i=nums.size()-1;i>=1;i--){
		swap(nums[0],nums[i]);//把当其最大的放置到数组末尾
		adjust(nums,i,0);
	}
	
}

int main(void){
	vector<int> nums={5,23,4,3,78,3,1,8,1,63,4,7};
	vector<int> temp=nums;
	show(nums);
	heapSort(nums);
	show(nums);


	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值