11.23学习笔记

一:选择排序

1.将元素分为已排序区和待排序区。

2.每一轮从待排序中选择最小值放到已排序区,直到待排序区没有元素为止。

void select_sort(int *arr, int l, int r) {
    for (int i = l; i < r-1 ; i++) {//注意最后剩下的元素,如果输入是l=0;r=6;排序0-6的元素,那么 
              第一个是<r-1;因为剩下一个不用排序(但要注意下面有(i+1);第二个是<=;因为都要参与排序
        int ind = i;
        for (int j = i + 1; j <=r; j++) {
            if (arr[j] < arr[ind])ind = j;
        }
        swap(arr[ind],arr[i]);
    }
    return ;
}
int main() {
   int a[10]={4,3,1,9,8,7,2};
   select_sort(a,0,6);
   for(int i=0;i<=6;i++)cout<<a[i]<<' ';
}

如何计算时间复杂度?第一次扫描n次,第二次扫描n-1次...第n次扫描1次,所以复杂度是o(n²)

二.插入排序:

void insert_sort(int *arr,int l,int r){
    for(int i=l+1;i<=r;i++){//注意这个和选择是倒过来的,第一位不需要排,后面的每一个都要排
        int j=i;//j代表当前要处理的元素。
        while(j>l&&arr[j-1]>arr[j]){//进入循环,开始向左边比较,找到自己的位置
            swap(arr[j-1],arr[j]);
            j--;
        }
    }
}

也和选择排序一样,分为已排序区和待排序区,但不同的是插入元素的时候放到合适的位置。

时间复杂度:对每一个插入的元素,插入调整次数的期望应该是n/2;

无监督的希尔排序:也即,我们开头就把最小值找出来并且放最左边,这样就不用判断i>l这个过程。

  void insert_sort(int *arr,int l,int r){
    int min=l;
    for(int i=l+1;i<=r;i++){
    if(arr[i]<arr[min])min=i;
    }
    swap(arr[l],arr[min]);
        for(int i=l+1;i<=r;i++){
            int j=i;
            while(arr[j-1]>arr[j]){
                swap(arr[j-1],arr[j]);
                j--;
            }
        }
        return;
    }

也就是说,最后一个元素调整(n-1)/2......所以 其实数量级都一样,都是o(n²)。

三.希尔排序:(基于插入排序的算法):(步长为分的组数)

那我们该如何设置步长序列呢?

void insert_sort(int arr[],int l,int r,int step){
    int min=l;
    for(int i=l+step;i<=r;i+=step){//这里要注意,for循环是在每次循环结束后进行变量增减操作,判断是在下一次循环开始,所以不会出现i越过r的问题。
        if(arr[i]<arr[min])min=i;
    }
    swap(arr[l],arr[min]);
    for(int i=l+step;i<=r;i+=step){
        int j=i;
        while(arr[j-step]>arr[j]){
            swap(arr[j-step],arr[j]);
            j-=step;
        }
    }
    return;
}
void shell_sort(int arr[],int l,int r){
    int step=1,n=r-l;
    while(step*2+1<n)step=step*2+1;//思考一下什么意思,事实上,我们的步长不需要大于n/2(否则就有1个人一组的,没意义,但因为在每次开头都会除以2,所以就改为<n;)
    do {
        step/=2;//
        for(int i=l;i<l+step;i++){
            insert_sort(arr,i,r,step);
        }

    }while(step>1);

四.冒泡排序

也将排序序列分区域。

冒泡排序其实 是每一轮将待排序区的最大值放到待排序区的最后一位,也就是已排序区的第一位。

 void bubble_sort(int *arr,int l,int r) {
    for(int i=r-1;i>=l+1;i--){
        for(int j=l;j<i;j++){
            if(arr[j]>arr[j+1])swap(arr[j],arr[j+1]);
        }
    }
    }

五.快速排序:

1.选定基准值。

2.左右两指针交叉排序。

3.得到小于基准值的左边序列,大于基准值的右边序列。

时间复杂度: 

如果每次左右区间都是平分,就是nlogn,如果都左边只有一个,那就是n。

void quick_sort(int *arr,int lx,int rx){
    int l=lx,r=rx,ind=arr[l];
    if(r-l<=1)return;
    while(l<r){
        while(l<r&&arr[r]>=ind)r--;
        if(l<r)arr[l++]=arr[r];
        while(l<r&&arr[l]<=ind)l++;
        if(l<r)arr[r--]=arr[l];
    }
    arr[l]=ind;
    quick_sort(arr,lx,l-1);
    quick_sort(arr,l+1,rx);

}

快速排序的优化:

①基于减少判断条件的优化:

②基于为了尽量平衡左右两边数量的优化(选取合适的基准值):

 三点取中法

③:单边递归法:

左半部分递归操作,右半部分本层循环。

     
六.归并排序:

#include <stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
void Merge(int *arr,int l,int r){
    if(l<r){
        int mid=(l+r)/2;
        Merge(arr,l,mid);
        Merge(arr,mid,r);
        int p1=l,p2=mid,k=0;
        int *temp=malloc(sizeof (int)*(r-l));
        while(p1<mid||p2<r){
            if(p2==r||(p1<mid&&arr[p1]<=arr[p2]))temp[k++]=arr[p1++];
            else temp[k++]=arr[p2++];
        }
        for(int i=l;i<r;i++)arr[i]=temp[i-l];
        free(temp);
        return;
    }
}
int main(){
  int a[10]={5,3,2,1,9,7,6,0,0,0};
  Merge(a,0,6);
    for(int i=0;i<7;i++)printf("%d",a[i]);
return 0;
}
————————————————

排序算法总结:

1.稳定排序:相同值的元素的相对顺序排序之后是否改变。

插入排序:因为比如说,我有前5和后5,当我把后5放入已排序区时,我是可以做到后5放在前5的后面的。

冒泡排序: 直接前后相等时,不交换。

归并排序: 当我们对左右数组归并时候,我们可以规定将相同值中左边数组的放到前面的位置。

2.非稳定排序:

选择排序:

...5||5...3...待排序区中的最小值3与排序区第一位5交换,改变了两个5的相对位置。

希尔排序:

5 5 3 8

快速排序:

假设基准值是5:5 ......3........3

堆排序:

1 3 2 2 4 5 4.

在线性排序时意味着3和第二个2发生了交换。

3.内外部排序:所谓的内外部排序,说的是是否一定要把数据全部读入到内存中才能排序。

内部排序:插入 冒泡 快速排序

外部排序:归并(归并的过程)

c++中sort函数的使用技巧:(一定要注意sort是左闭右开的!)

1.sort对数组进行从大到小的排序:

sort(arr,arr+23,greater<int>());

2.sort对vector进行排序

sort(arr.begin(),arr.end(),greater<int>());

3.对一些自己规定的数据类型排序.

 struct Data{
       int t,p;
   };

vector<Data>arr;
sort(arr.begin(),arr.end(),cmp);
bool cmp(const Data &a,const Data &b){
if(a.t!=b.t)return a.t<b.t;
return a.p<b.t;}

4.不改变原数组,只给出原数组排序的索引:

 int arr[6]={7,4,5,1,3,2};
    int ind[6]={0,1,2,3,4,5};//这是arr数组排序的索引值
    sort(ind,ind+6,[&](int i,int j)->bool{return arr[i]<arr[j];});//这句话的意思是,按照arr数组中相应元素的大小对ind数组进行排序。

LC01:两数之和:

我超太妙了!!用杨氏矩阵可以证明其正确性!

 

如果直接遍历整个矩阵,找到等于x的值,那么时间复杂度就是o(n²), 

但是,我们如果先从右上角开始,这个元素有什么特点?他是第一行的最大值,是最后一列的最小值。所以如果右上角的值都比x小了,那么最后一列直接都不可能,所以左移动一位,倒数第二列。表现为右指针向左移动一位。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> a = {0, 0};
        for (int i = 0; i <nums.size(); ++i) {
            for (int j = i + 1; j <nums.size(); ++j) {
                if (nums[i] + nums[j] == target) {
                    a[0] = i;
                    a[1] = j;
                    return a;
                }
            }
        }
        return a;
    }
};
//时间复杂度n²,没意思。
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int n=nums.size();
        vector<int>ind(n);
        for(int i=0;i<n;i++)ind[i]=i;
        sort(ind.begin(),ind.end(),[&](int i,int j)->bool{return nums[i]<nums[j];});
        int p1=0;int p2=n-1;
        while(nums[ind[p1]]+nums[ind[p2]]!=target){
            if(nums[ind[p1]]+nums[ind[p2]]<target)p1++;
            else p2--;
        }
        vector<int>ans(2);
        ans[0]=ind[p1];ans[1]=ind[p2];
        return ans;
};
};

  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值