排序算法思路整理

排序算法思路整理

个人理解,主要是给自己看的,文字较为通俗,见谅

是否稳定:是否会改变相同元素的相对顺序

冒泡排序(稳定)

思路 :以升序为例,从第一个元素开始,与下一个元素做比较,如果前一个元素大于后一个元素,则进行交换,否则直接++,每次大的元素做交换往后移,则第一趟遍历下来,最大的元素,已经到了最后,重复操作,n个元素需要 n-1 趟的遍历就会完全有序。

void Bubblesort(int *arr,int len)
{
    int tmp=0;
    for(int i=0;i<len-1;i++)
    {
        //bool flag = false;   优化
        for(int j=0;j<len-1-i;j++)
        {
            if(arr[j] > arr[j+1])
            {
                tmp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=tmp;
                //flag = true;
            }
        }
        //if(flag == false)  break;
    }
}

时间复杂度 : O(n^2)

空间复杂度 : O(1)

优化方面 :可以设置一个bool类型的变量做标识,初始化为false,交换就赋值为true,若某一趟遍历没有发生交换,则说明元素已经完全有序,直接跳出循环,无需再遍历,但是个人认为优化其实无必要,既然已经用了冒泡,那么再怎么优化,效率方面提升也不会很大。

快速排序(不稳定)

递归思路 :以升序为例,从n个元素从选出一个元素作为基准(一般为待排序元素序列的首元素),用一变量保存,取两个数left与right分别做待排序元素序列中第一个元素与最后一个元素的下标,从right开始,往前遍历,直到找到第一个小于基准的元素,将其值赋给left下标的元素,再从left开始往后遍历,直到找到第一个大于基准的元素,将其值赋给right下标的元素,只要left<right,就反复循环操作,跳出循环时应该是left==right,该位置就是基准元素在完全有序时应在的位置,将基准赋在该位置并返回下标,此为一次划分。快排递归思路就是调用一次划分函数,当返回值左右两边的待排序元素长度大于等于2时,就需要继续进行划分,若左边待排序元素需要继续划分,则原left不变,以返回值-1为新right,递归调动快排函数,若右边待排序元素需要继续划分,则原right不变,以返回值+1为新left递归调动快排函数,直到待排序元素只剩一个就自然有序了,那么整体序列也就完全有序了。

static int Partition(int *arr,int left,int right)
{
    int tmp=arr[left];
    while(left<right)
    {
        while(left<right && arr[right]>=tmp)
        {
            right--;
        }
        arr[left] = arr[right];
        
        while(left<right && arr[left]<=tmp)
        {
            left++;
        }
        arr[right] = arr[left];
    }
    arr[left] = tmp;
    return left;
}
static void Quick(int *arr,int left,int right)
{
    int tmp = Partition(arr,left,right);
    if(left<tmp-1)
    {
        Quick(arr,left,tmp-1);
    }
    if(right>tmp+1)
    {
        Quick(arr,tmp+1,right);
    }
}
void Quicksort(int *arr,int len)
{
    Quick(arr,0,len-1);
}

时间复杂度在这里插入图片描述

空间复杂度在这里插入图片描述

非递归实现 :

static int Partition(int *arr,int left,int right)
{
    int tmp=arr[left];
    while(left<right)
    {
        while(left<right && arr[right]>=tmp)
        {
            right--;
        }
        arr[left] = arr[right];
        
        while(left<right && arr[left]<=tmp)
        {
            left++;
        }
        arr[right] = arr[left];
    }
    arr[left] = tmp;
    return left;
}
static void Quick(int *arr,int left,int right)
{
    assert(left<right);
    
    stack<int> m;
    int mid=Partition(arr,left,right);
    if(left<mid-1)
    {
        m.push(left);
        m.push(mid-1);
    }
    if(right>mid+1)
    {
        m.push(mid+1);
        m.push(right);
    }
    while(!m.empty())
    {
        int r=m.top();
        m.pop();
        int l=m.top();
        m.pop();
        mid=Partiton(arr,l,r);
        if(l<mid-1)
        {
            m.push(l);
            m.push(mid-1);
        }
        if(r>mid+1)
        {
            m.push(mid+1);
            m.push(r);
        }
    }
    
}
void Quicksort(int *arr,int len)
{
    Quick(arr,0,len-1);
}

直接插入排序(稳定)

思路 :以升序为例,从第2个元素开始遍历,前面只有一个元素,故可直接认为有序,让第二个元素与前面的元素做比较,找到第一个比自身小的元素,直接插在其后面,然后后面的元素,以此类推

void Insertsort(int *arr,int len)
{
    int tmp=0;
    for(int i=1;i<len;i++)
    {
        tmp=arr[i];
        int j=i-1;
        while(j>=0 && arr[j]>tmp)
        {
            arr[j+1]=arr[j];
            j--;
        }
        arr[j+1]=tmp;
    }
}

时间复杂度 :O(n^2)

空间复杂度 :O(1)

希尔排序(不稳定)

思路 :本质而言,其实还是插入排序,按下标的一定增量将待排序元素序列分成若干组,然后使用直接插入排序,然后缩小该增量,继续进行直接插入排序,当该增量缩小至1时,整个序列就是一组,再进行直接插入排序。

static void Shell(int *arr,int len,int gap)
{
    for(int i=gap;i<len;i++)
    {
        int tmp=arr[i];
        int j=i-gap;
        while(j>=0 && arr[j]>tmp)
        {
            arr[j+gap]=arr[j];
            j-=gap;
        }
        arr[j+gap]=tmp;
    }
}
void Shellsort(int *arr,int len)
{
    int gaps[]={5,3,1};
    for(int i=0 ; i < sizeof(gaps)/sizeof(gaps[0]) ; i++)
    {
        Shell(arr,len,gaps[i]);
    }
}

时间复杂度 :O(n^1.3)

空间复杂度 :O(1)

直接选择排序(不稳定)

思路 :从待排序序列中找到值最小的元素,如果该元素不是第一个元素,就与第一个元素进行交换,然后从余下元素中找到最小元素,若不是第二个元素与第二个元素交换,以此类推。

void Selectsort(int *arr,int len)
{
    int tmp=0;
    for(int i=0;i<len-1;i++)
    {
        int min=i;
        for(int j=i+1;j<len;j++)
        {
            if(arr[j]<arr[min])
            {
                min=j;
            }
        }
        if(min != i)
        {
            tmp=arr[i];
            arr[i]=arr[min];
            arr[min]=tmp;
        }
    }
}

时间复杂度 :O(n^2)

空间复杂度 :O(1)

堆排序(不稳定)

思路 :大顶堆(每个结点的值都大于等于左右孩子节点的值),小顶堆(每个结点的值都小等于左右孩子节点的值),堆排序就是构建一个大顶堆(升序用大顶堆,降序用小顶堆),此时根节点就是最大值,将其与末尾结点交换,然后将余下元素结点,重新调整为大顶堆,找出次大值与倒数第二个交换,以此类推,直到序列完全有序。

void Adjust(int *arr,int start,int end)
{
    int tmp=0;
    for(int i=start*2+1;i<=end;i=i*2+1)
    {
        if(i+1<=end && arr[i]<arr[i+1])
        {
            i++;
        }
        if(arr[(i-1)/2]<arr[i])
        {
            tmp=arr[(i-1)/2];
            arr[(i-1)/2]=arr[i];
            arr[i]=tmp;
        }
    }
}
void Heapsort(int *arr,int len)
{
    for(int i=(len-1-1)/2;i>=0;i--)
    {
        Adjust(arr,i,len-1);
    }
    for(int j=len-1;j>=0;j--)
    {
        int tmp=arr[j];
        arr[j]=arr[0];
        arr[0]=tmp;
        Adjust(arr,0,j-1);
    }
}

时间复杂度在这里插入图片描述

空间复杂度 : O(1)

基数排序(稳定)

思路 :构建10个队列分别标识09,找到待排序序列中元素的最大值,并得到其位数,这是元素入队出队的次数,由最低位开始,按照该位上的值入相应的队列,然后按09顺序出队,再按高一位的值进行入队出队,直至最高位,最后一次出队时,则完全有序

int Gerfig(int *arr,int len)
{
    int max=0;
    for(int i=0;i<len;i++)
    {
        if(arr[i]>max)
        {
            max=arr[i];
        }
    }
    int fig=0;
    while(max!=0)
    {
        max/=10;
        fig++;
    }
    return fig;
}

int Getnum(int n,int fig)
{
    while(fig!=0)
    {
       n/=10;
       fig--;
    }
    return n%10;
}

void Radix(int *arr,int len,int fig)
{
    queue<int> ma[10];
    int m;
    for(int i=0;i<len;i++)
    {
        m=Getnum(arr[i],fig);
        ma[m].push(arr[i])
    }
    int k=0;
    for(int j=0;j<10;j++)
    {
        while(!ma[j].empty())
        {
            arr[k++]=ma[j].front();
            ma[j].pop();
        }
    }
}

void Radixsort(int *arr,int len)
{
    int fig=Getfig(arr,len);
    for(int i=0;i<fig;i++)
    {
        Radix(arr,len,i);
    }
}

时间复杂度 :O(d(n+r)) //d长度 r关键字基数 n关键字个数

空间复杂度 :O(n+rd)

归并排序(稳定)

思路 :简单来说,归并排序就是将两个有序序列合并成一个有序序列,而当一个序列只包含一个元素时,自然可将它认为有序,故可将n个元素的待排序序列,当作n个有序子序列,然后利用归并排序不断两两合并,直到最后只剩下两个有序序列再进行合并,成为一个完全有序的序列

static void Merge(int *arr,int len,int gap)
{
    int low1=0;
    int high1=low1+gap-1;
    int low2=high1+1;
    int high2=low2+gap-1<len?low2+gap-1:len-1;
    int *brr=(int *)malloc(len*sizeof(int));
    
    int i=0;
    while(low2<len)
    {
        while(low1<=high1 && low2<=high2)
        {
            if(arr[low1]<=arr[low2])
            {
                brr[i++]=arr[low1++];
            }
            else
            {
                brr[i++]=arr[low2++];
            }
        }
        
        while(low1<=high1)
        {
            brr[i++]=arr[low1++];
        }
        while(low2<=high2)
        {
            brr[i++]=arr[low2++];
        }
        
        low1=high2+1;
        high1=low1+gap-1;
        low2=high1+1;
        high2=low2+gap-1<len?low2+gap-1:len-1;
    }
    
    while(low1<len)
    {
        brr[i++]=arr[low1++];
    }
    for(i=0;i<len;i++)
    {
        arr[i]=brr[i];
    }
    free(brr);
}
void Mergesort(int *arr,int len)
{
    for(int i=1;i<len;i*=2)
    {
        Merge(arr,len,i);
    }
}

时间复杂度在这里插入图片描述

空间复杂度 : O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
,发送类别,概率,以及物体在相机坐标系下的xyz.zip目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值