1.冒泡排序(有序O(N),最差O(N^2),平均O(N^2) ,稳定)
基本思想:外层循环控制次数,内层是两两比较,把每一轮未排定部分最大的元素放到了数组的末尾。
vector<int> sortArray(vector<int>& nums) {
for(int i = 1;i < nums.size(); i++) {//i表示趟数,共n-1趟
bool swaped = false;
for(int j = 0; j < nums.size() - i; j++) {//每趟减少1个。
if(nums[j] > nums[j+1]) {//相等不交换,所以稳定
swap(nums[j+1], nums[j]);
swaped = true;
}
}
if(!swaped)return nums;
}
return nums;
}
2.选择排序(最好O(N)已有序, 最坏O(N^2),平均O(N^2) ,稳定)
还是两层for循环,第一层控制移动第i个位置,第二层选择当前最小的数放置到该位置。通俗的说,就是第一次选最小的元素与num[0]交换,第二次从num[1]开始选择最小元素与num[1]交换……
vector<int> sortArray(vector<int>& nums) {
//共选择n-1次
for(int i=0;i<nums.size()-1;i++){
//先令min为当前位置元素
int min=i;
//每一次都选择到最后一个元素
for(int j=i+1;j<nums.size();j++){
//选择最小的元素
min=nums[min]<nums[j]?min:j;
}
//交换
swap(nums[i],nums[min]);
}
return nums;
}
3.插入排序
两层for循环,第一层控制当前元素,第二层确定该元素要被插入到已经排序好的哪个位置。
vector<int> sortArray(vector<int>& nums) {
for(int i=1;i<nums.size();i++){//默认[0]位置已经排序好,从后一个位置开始
//该元素的前一个位置[j]-开始位置[0]已经排序好
for(int j=i-1;j>=0 && nums[j]>nums[j+1];j--){
swap(nums[j],nums[j+1]);
}
}
return nums;
}
4.归并排序(O(nlogn),)
分治的思想,一分为二,先让左边右边都排序,再new一个新的辅助数组,两个指针分别指向左右两边的第一个元素,谁小就放置哪个元素。
class Solution {
public:
vector<int> temp;
vector<int> sortArray(vector<int>& nums) {
temp = vector<int>(nums.size(), 0);
mergesort(0, nums.size() - 1,nums);
return nums;
}
void mergesort(int l,int r,vector<int>& nums){
if (l >= r) return;
int mid=(l+r)/2;
//左右都排序
mergesort(l,mid,nums);
mergesort(mid+1,r,nums);
int i=0;
int p1=l; //p1p2两个指针
int p2=mid+1;
while(p1<=mid && p2<=r){
//将小的元素放入辅助数组
temp[i++]=nums[p1]<=nums[p2]?nums[p1++]:nums[p2++];
}
//没有越过边界的剩余元素
while(p1<=mid )temp[i++]=nums[p1++];
while(p2<=r )temp[i++]=nums[p2++];
//拷贝入原数组
for (i = 0; i < r - l + 1; ++i) nums[l + i] = temp[i];
}
};
归并的扩展:
逆序对:
实际是归并的过程,只需在排序的途中记录下逆序的个数。
class Solution {
public:
int res=0;
vector<int> temp;
int reversePairs(vector<int>& nums) {
temp = vector<int>(nums.size(), 0);
return mergesort(0, nums.size() - 1,nums);
}
int mergesort(int l,int r,vector<int>& nums){
if (l >= r) return 0;
int mid=(l+r)/2;
mergesort(l,mid,nums);
mergesort(mid+1,r,nums);
int i=0;
int p1=l;
int p2=mid+1;
//int* temp = new int[right-left+1];
while(p1<=mid && p2<=r){
if(nums[p1]>nums[p2]){
temp[i++]=nums[p2++];
res+=mid-p1+1;
}else{
temp[i++]=nums[p1++];
}
}
while(p1<=mid )temp[i++]=nums[p1++];
while(p2<=r )temp[i++]=nums[p2++];
for (i = 0; i < r - l + 1; ++i) nums[l + i] = temp[i];
return res;
}
};
小和问题:(代码暂时还有点问题)
在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。
{1,3,4,2,5}
1左边比1小的数,没有
3左边比3小的数,1;
4左边比4小的数,1、3;
2左边比2小的数,1;
5左边比5小的数,1、3、4、2;
所以小和为1+1+3+1+1+3+4+2=16
#include<iostream>
#include <vector>
#include <windows.h>
using namespace std;
int merge1(vector<int>num,int l,int r);
vector<int> temp;
int cont=0;
int merge1(vector<int>num,int l,int r){
if(l>=r)return 0;
int mid=(l+r)/2;
merge1(num,l,mid);
merge1(num,mid+1,r);
int i=0,p1=l,p2=mid+1;
while(p1<=mid && p2<=r){
if(num[p1]<num[p2]){
temp[i++]=num[p1];
cont+=(r-p2+1)*num[p1];
p1++;
}else{
temp[i++]=num[p2++];
}
}
while(p2<=r)temp[i++]=num[p2++];
while(p1<=mid)temp[i++]=num[p1++];
for(auto c:temp)num[i+l]=temp[i];
return cont;
}
int main(){
int n;
cin>>n;
int a;
temp=vector<int>(n);
vector<int> num;
for (int i=0;i<n;i++){
cin>>a;
num.push_back(a);
}
merge1(num,0,n-1);
cout<<cont<<endl;
system("pause");
}