冒泡排序
基础版,本来想着加flag减少多余的计算,但是我这样做好像已经自动将多余的运算避免了。
写了后面的排序算法,发现我这样写思路就跟插入排序很像了。。百度后发现冒泡排序的取值应当是从nums.size() 到1 ,所以下面完全是不伦不类的插入排序。
void swap(vector<int>& nums,int x,int y){
int temp=nums[x];
nums[x]=nums[y];
nums[y]=temp;
}
void bubble(vector<int>& nums){
for(int j=1;j<nums.size();j++){
for(int i=j;i>0 and nums[i-1]>nums[i];i--){
swap(nums,i-1,i);
}
}
}
正宗的冒泡排序是通过相邻两两比较将较大的数一步步浮出
void bubble(vector<int>& nums){
bool flag=true;//添加一个变量监督剩下的排序已排好,不必要继续排序
for(int j=nums.size();j>0 and flag==true;j--){
flag=false;
for(int i=1;i<j;i++){
if(nums[i-1]>nums[i])
swap(nums,i-1,i);
flag=true;
}
}
}
选择排序
每次交换当前与最小的
void select(vector<int>& nums){
for(int i=0;i<nums.size()-1;i++){
int temp=i;
for(int j=i;j<nums.size();j++){
if(nums[j]<nums[temp])
temp=j;
}
swap(nums,i,temp);
}
}
插入排序
将当前值插入之前合适的位置
void insert(vector<int>& nums){
int j,temp;
for(int i=1;i<nums.size();i++){
temp=nums[i];
j=i;
while(j>0 and nums[j-1]>temp){
nums[j]=nums[j-1];
j--;
}
nums[j]=temp;
}
}
希尔排序
是一个分组插入的方法,插入排序的改进版。特点不稳定,与取的增量序列gap的取值相关性很大。
等于是每隔gap个数分出一个数列执行一次插入排序,一个分出gap个小数列插入排序后,做到整体有序再整体插入排序
void shell(vector<int>& nums){
int j,temp;
int gap=nums.size()/3;
while(gap>=1){
for(int i=gap;i<=nums.size()-gap;i++){
temp=nums[i];
j=i;
while(j>=gap and nums[j-gap]>temp){
nums[j]=nums[j-gap];
j-=gap;
}
nums[j]=temp;
}
gap/=2;
}
}
堆排序
堆近似完全二叉树,分为大顶堆(每个结点的值都大于左右子结点的值),小顶堆(每个结点的值都小于左右子结点的值)。
由于使用的vector,所以下标麻烦了些。堆排序的下标需要从 1 开始
堆排序思路是按大顶堆的思路,每次找到最大值,将最大值与末尾元素swap,再忽略最后一个元素将剩下的重新调整为大顶堆。
class Solution {
public:
void main(vector<int>& nums) {
heap(nums);
for(int i=0;i<nums.size();i++) cout<<nums[i]<<' ';
}
void heap(vector<int>& nums){
int size=nums.size();
int temp;
for(int i=size/2;i>=0;i--)//将原始序列构成大顶堆
heapadjust(nums,i,size);
for(int i=size-1 ;i>1;i--){
temp=nums[0];
nums[0]=nums[i];
nums[i]=temp;//将最大值与末尾元素调换位置,剩下的重新构成大顶堆
heapadjust(nums,0,i);
}
}
void heapadjust(vector<int>& nums,int s,int length){
int temp=nums[s];
int x=s+1;
for(int i=2*x;i<length;i*=2){
if(nums[i-1]<nums[i])
i+=1;
if(temp>=nums[i-1])
break;
nums[x-1]=nums[i-1];
x=i;
}
nums[x-1]=temp;
}
};
快速排序
基本方法
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
Qsort(nums,0,nums.size()-1);
for(int i=0;i<nums.size();i++) cout<<nums[i]<<' ';
return 0;
}
void swap(vector<int>& nums,int x,int y){
int temp=nums[x];
nums[x]=nums[y];
nums[y]=temp;
}
void Qsort(vector<int>& nums, int begin, int end){
int pivot;
if(begin<end){
pivot=partition(nums,begin,end); //找中间值,将nums小的左边,大的右边
Qsort(nums,begin,pivot-1);
Qsort(nums,pivot+1,end);
}
}
int partition(vector<int>& nums,int low,int high){
int pivotkey=nums[low];
int temp;
while(low<high){
while(low<high && nums[high]>=pivotkey) high--;
swap(nums,low,high);
while(low<high && nums[low]<=pivotkey) low++;
swap(nums,low,high);
}
return low;
}
};
优化了选择pivot,和减少了不必要的交换。
class Solution {
public:
void main(vector<int>& nums) {
Qsort(nums,0,nums.size()-1);
for(int i=0;i<nums.size();i++) cout<<nums[i]<<' ';
}
void swap(vector<int>& nums,int x,int y){
int temp=nums[x];
nums[x]=nums[y];
nums[y]=temp;
}
void Qsort(vector<int>& nums, int begin, int end){
int pivot;
if(begin<end){
pivot=partition(nums,begin,end); //找中间值,将nums小的左边,大的右边
Qsort(nums,begin,pivot-1);
Qsort(nums,pivot+1,end);
}
}
int partition(vector<int>& nums,int low,int high){
int pivotkey;
int middle=low+(high-low)/2;
if(nums[middle]>nums[high]) swap(nums,middle,high);
if(nums[low]>nums[high]) swap(nums,low,high);
if(nums[low]<nums[middle]) swap(nums,middle,low);
pivotkey=nums[low];//中值换到low的位置上
while(low<high){
while(low<high && nums[high]>=pivotkey) high--;
nums[low]=nums[high];//减少不必要的交换,改为闭合赋值;
while(low<high && nums[low]<=pivotkey) low++;
nums[high]=nums[low];
}
nums[low]=pivotkey;
return low;
}
};
归并排序
递归实现
class Solution {
public:
void main(vector<int>& nums) {
Merging(nums,0,nums.size()-1);
for(int i=0;i<nums.size();i++) cout<<nums[i]<<' ';
}
void Merging(vector<int>& nums,int x,int y){
int mid=(x+y)/2;
if(x<y){
Merging(nums,x,mid);
Merging(nums,mid+1,y);
Mergsort(nums,x,mid,y);
}
}
void Mergsort(vector<int>& nums,int x,int m,int y){
cout<<x<<' ';
cout<<m<<' ';
cout<<y<<endl;
const int N=204800;
int n1=m-x+1,n2=y-m;
vector<int> left(n1+1),right(n2+1);
for(int i=0;i<n1;i++) left[i]=nums[x+i];
left[n1]=N;
for(int j=0;j<n2;j++) right[j]=nums[m+1+j];
right[n2]=N;
int i=0,j=0;
for(int k=x;k<y+1;k++){
if(left[i]<right[j]){
nums[k]=left[i];
i++;
}
else{
nums[k]=right[j];
j++;
}
}
}
};
桶排序
这是简单版的桶排序代码,正式版本的思路应该是
- 将待排序元素划分到不同的桶。先扫描一遍序列求出最大值 maxV 和最小值 minV ,设桶的个数为 k ,则把区间 [minV, maxV] 均匀划分成 k 个区间,每个区间就是一个桶。将序列中的元素分配到各自的桶。
- 对每个桶内的元素进行排序。可以选择任意一种排序算法。
- 将各个桶中的元素合并成一个大的有序序列。
- 假设数据是均匀分布的,则每个桶的元素平均个数为 n/k 。假设选择用快速排序对每个桶内的元素进行排序,那么每次排序的时间复杂度为 O(n/klog(n/k)) 。总的时间复杂度为 O(n)+O(m)O(n/klog(n/k)) = O(n+nlog(n/k)) = O(n+nlogn-nlogk 。当 k 接近于 n 时,桶排序的时间复杂度就可以金斯认为是 O(n) 的。即桶越多,时间效率就越高,而桶越多,空间就越大。
计数排序与基数排序都是桶排序的一种。
void bucket(vector<int>& nums){
//查找最大最小值
int max=0,min=204800;
for(int i=0;i<nums.size();i++){
if(nums[i]>max) max=nums[i];
if(nums[i]<min) min=nums[i];
}
//创建桶并计数
vector<int> temp(max+1,0);
for(int i=0;i<nums.size();i++){
temp[nums[i]]++;
}
for(int i=0;i<temp.size();i++) cout<<temp[i]<<' ';
//将数字按桶放回
int j=0;
for(int i=min;i<=max;i++){
while(temp[i]-->0){
cout<<temp[i]<<' '<<i<<' '<<j<<endl;
nums[j++]=i;
}
}
}