排序算法总结|数组和链表实现的对比|leetcode c++_lemonade13的博客-程序员宅基地

技术标签: c++  code  DS  

排序算法对比一览图

类别 方法 数组实现 链表实现 稳定 适用场景
时间复杂度 空间复杂度 时间复杂度 空间复杂度
插入排序 直接插入

O(n^2)

O(1) O(n^2) O(1) 在数列近乎可下降到O(n)
shell排序 O(nlogn) O(1) - - 延续了上一思想
交换排序 冒泡排序 O(n^2) O(1) O(n^2) O(1)  
快速排序 O(nlogn)

非递归:O(1)

递归:O(logn) ~ O(n)

O(nlogn) 不考虑递归:

O(1)

改进:

1)小partition上:插入排序

2)重复元素多:头尾指针 or 三路快排

选择排序 直接选择 O(n^2) O(1) O(n^2) O(1)  
堆排序 O(nlogn) O(1) - -  
归并排序 O(nlogn) O(n) O(nlogn) O(1)  
桶排序          

 

算法详解

快速排序

一个细节:在做partition时,为什么要从头尾两个方向向中间进行粗排序?

使得分割的左右两部分元素数量更均衡。只有一个方向遍历的话,等于key的元素分布会堆积在同一边;两个方向遍历的话,判断里都覆盖(或都不覆盖)等于key的元素,就能避免堆积。

数组实现

(可直接运行)

编程心得:两个指针实际含义是 一个指向坑位,一个找新坑位。

leetcode第912题

#include <iostream>
using namespace std;
void print(int nums[], int l, int r){
    for(int i=l; i<=r; ++i){
        cout<<nums[i]<<" ";
    }
    cout<<endl;
}
void sort(int nums[], int l, int r){
    if(l>=r) return;
    int key = nums[l];
    int il = l, ir = r;
    while (il<ir) {
        while(il<ir && nums[ir]>=key){
            --ir;
        }
        if(il<ir) nums[il++] = nums[ir];
        while(il<ir && nums[il]<=key){
            ++il;
        }
        if(il<ir) nums[ir--] = nums[il];
    }
    nums[il] = key;
    sort(nums, l, il-1);
    sort(nums, il+1, r);
}

int main(int argc, const char * argv[]) {
    int nums[] = {2,4,1,3,2};
    print(nums,0,4);
    sort(nums, 0, 4);
    print(nums,0,4);
    return 0;
}

链表实现

(leetcode第148题)

点1:链表中元素无法直接访问,导致找坑不能跳着找,因此解决办法是从前向后捋,记录前小后大的分界线,把未排序中小的往分界线放。

点2:key元素的坑位最后决定,但由于链表中无法直接访问,key一旦换开就很难找到,因此排序时先不要占用key的坑位,只在最后把头部的key和分界线上小的元素位置交换。

变量含义:p用来记录分界线上小于一边的元素,q用来找未排序中需要往前调动的小于的元素。

运行结果:实现一速度和内存略少于实现二。

实现一:链表不动,子链用首尾元素来判别。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head==NULL || head->next==NULL) return head;
        sort(head, NULL);
        return head;
    }
    void sort(ListNode* head, ListNode* end){
        if(head==end || head->next == end) return;
        int key = head->val;
        ListNode *p = head, *q = head->next;
        bool isok = true;
        while(q!=end){
            if(q->val < key){
                p = p->next;
                swap(p->val, q->val);
            }
            q = q->next;
        }
        swap(p->val, head->val);
        sort(head, p);
        sort(p->next, end);
    }
    void swap(int &p, int &q){
        int tmp = q;
        q = p;
        p = tmp;
    }
};

实现二:断开链表,子链是拆成单独的链。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head==NULL || head->next==NULL) return head;
        ListNode *tmp = head->next;
        ListNode *less = new ListNode(0);
        ListNode *big = new ListNode(0);
        ListNode *i = big, *j = less;
        while(tmp!=NULL){
            if(tmp->val >= head->val){
                i->next = tmp;
                i = i->next;
            }else{
                j->next = tmp;
                j = j->next;
            }
            tmp = tmp->next;
        }
        i->next = NULL;
        j->next = NULL;
        ListNode *left = sortList(less->next);
        ListNode *right = sortList(big->next);
        if(left!=NULL){
            i = left;
            while(i->next!=NULL){
                i = i->next;
            }
            i->next = head;
        }
        head->next = right;
        return (left)?left:head;
    }
};

 

归并排序

自顶向下:不断二分,逐个合并有序子列。

数组实现

(代码可直接运行)

#include <iostream>
using namespace std;

void print(int nums[], int len){
    for(int i=0; i<len; ++i){
        cout<<nums[i]<<" ";
    }
    cout<<endl;
}

void merge(int nums[], int l, int mid, int r){
    int tmp[r-l+1];
    int itmp = 0, ir = mid+1, il = l;
    while(il<=mid && ir<=r){
        if(nums[il]<=nums[ir]){
            tmp[itmp] = nums[il++];
        }else{
            tmp[itmp] = nums[ir++];
        }
        ++itmp;
    }
    while(il<=mid){
        tmp[itmp++] = nums[il++];
    }
    while(ir<=r){
        tmp[itmp++] = nums[ir++];
    }
    itmp = 0;
    il = l;
    while(itmp<r-l+1){
        nums[il++] = tmp[itmp++];
    }
    print(nums,4);
}

void sort(int nums[], int l, int r){
    if(l>=r) return;
    int mid = (l + r) / 2;
    sort(nums, l, mid);
    sort(nums, mid+1, r);
    merge(nums, l, mid, r);
}

int main(int argc, const char * argv[]) {
    int nums[] = {4,2,1,3};
    sort(nums, 0, 3);
    print(nums, 4);
    return 0;
}

链表实现

(leetcode第148题,可直接运行)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head==NULL || head->next==NULL) return head;
        ListNode *t1 = head, *t2 = head;
        while(t2!=NULL && t2->next != NULL){
            t2 = t2->next->next;
            if(t2==NULL) break;
            t1 = t1->next;
        }
        t2 = t1->next;
        t1->next = NULL;
        ListNode* l1 = sortList(head);
        ListNode* l2 = sortList(t2);
        return merge(l1, l2);
    }
    ListNode* merge(ListNode* l1, ListNode* l2){
        if(l1==NULL) return l2;
        if(l2==NULL) return l1;
        ListNode* node = new ListNode(0);
        ListNode *tail = node;
        while(l1!=NULL && l2!=NULL){
            if(l1->val <= l2->val){
                tail->next = l1;
                l1 = l1->next;
            }else{
                tail->next = l2;
                l2 = l2->next;
            }
            tail = tail->next;
            tail->next = NULL;
        }
        if(l1!=NULL){
            tail->next = l1;
        }
        if(l2!=NULL){
            tail->next = l2;
        }
        return node->next;
    }

};

 

参考:

1.数组实现的排序算法对比:https://blog.csdn.net/yushiyi6453/article/details/76407640

https://blog.csdn.net/wuxinyicomeon/article/details/5996675

2.链表实现对比:https://www.cnblogs.com/TenosDoIt/p/3666585.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lemonade13/article/details/104202927

智能推荐

计算机组成原理期末复习题_亿钱君的博客-程序员宅基地

这里写目录标题一级目录二级目录三级目录第一章:计算机系统概述1:选择题第二章:数据在计算机中的表示一.选择题二.填空题三.判断题四.计算题一级目录二级目录三级目录第一章:计算机系统概述1:选择题微型计算机的发展以( )技术为标志。A、操作系统B、微处理器C、磁盘D、软件正确答案: B下列选项中,不属于计算机系统软件的是( )。A、操作系统B、服务程序C、语言处理程序D、自动控制程序正确答案: D冯·诺依曼机工作方式具有以下哪个特点( )?A、多指令流单数据流B、按地址

Android Looper And Hander 机制剖析 - 02_feng1456的博客-程序员宅基地

在第一篇中,我们使用了Handler,但是Handler处理任务的进程和Activity都是在主线程中,这样我们还是无法实现把任务交给他们现成处理的目标,因为主线程处理耗时操作最多只有5秒,否则会引发ANR错误。在Java中,我们使用多现成来处理任务,在Android中,我们如何来使用多现成处理呢。其实也是很简单的。1.MainActivityimport com.example.hand

zedboard如何从PL端控制DDR读写(三)——AXI-FULL总线调试_ReStart_11的博客-程序员宅基地

本文主要是总结一下使用AXI-FULL调试的过程。    首先想到的是用RAM IP核来测试,方法是通过AXI接口向RAM写入一组数据并读出,看起来很简单,然而试了好久都没能出结果。如下图所示,其实AXI RAM就是在本地RAM接口的基础上套了一个AXI的壳    在使用modelsim仿真的时候总是会抛出一个警告,具体的警告类型忘了,下次有机会再尝试。试了好多次都

jvm最大最小内存参数设置_jvm最小内存_huayang183的博客-程序员宅基地

-Xms 为jvm启动时分配的初始堆的大小,也是堆大小的最小值,比如-Xms200m,表示分配200M-Xmx 为jvm运行过程中分配的最大堆内存,比如-Xmx500m,表示jvm进程最多只能够占用500M内存-Xss 为jvm启动的每个线程分配的内存大小,默认JDK1.4中是256K,JDK1.5+中是1M...

ZBrush系列——纯小白入门篇(六)_chenchen6668的博客-程序员宅基地

学会使用Z球,Z球在zbrush中是一个很好用的快速粗模的搭建工具,我们可以用来非常方便的创建一些基本形状出来,再进行细分或是雕刻就非常方便了。1.首先找到Z球的位置如图所示:2.在视图中拖出一个来,并进入编辑模式。3.直接拖拽就可以在第一个Z球上再增加一个新的Z球4.按A键可以直接预览到Z球变成网格之后的形状,再按一次A就可以回...

随便推点

Unity2018的shader中LIGHT_ATTENUATION()报错的解决方案_天富儿的博客-程序员宅基地

文章目录描述错误原因修改后参考描述错误在将Unity5.5.0版本的项目转换成Unity2018.1.1的项目时,一个玻璃的shader报错了。错误信息:Shader error in ‘Shader Forge/Examples/Refraction’: syntax error: unexpected token ‘;’ at line 261 (on d3d11)根据上面的报错信息,我们定位错误位置:错误代码:float attenuation = LIGHT_ATTEN

中兴交换机基本配置(一)_weixin_33734785的博客-程序员宅基地

一、系统的启动过程如下。1、上电后,首先进行硬件启动,当硬件检测无误后,管理终端上出现下列信息:WelcometouseZTEeCarrier!!Copyright(c)2004-2006,ZTECo.,Ltd.SystemBooting......CPU:S3C45010ARM7TDMIBSPversion:1.2/0C...

Matlab中函数句柄总结复盘(一)_函数句柄例子_Jeossirey的博客-程序员宅基地

问:f=@(x)acos(x)表示什么意思?其中@代表什么?今天杰哥给大家介绍一下函数句柄的详细知识。首先我们先看一个问题:表示什么意思呢?其中的@代表什么呢?我们来揭晓一下答案:f是函数句柄;@是定义句柄的运算符;相当于建立了一个函数文件:% 建立函数文件f.mfunctiony=f(x)y=cos(x);再给大家举个例子:则相当于建立了一个函数文件:%建立xsqual函数function y=xsqual(x)y=x^2+2*x+1;我们再做一个详细说明:.

iOS支持WKWebView的Hybrid开源框架GPHybrid_coder大鹏的博客-程序员宅基地

GPHybrid ExampleTo run the example project, clone the repo, and run pod install from the Example directory first.Introduction前言Hybrid框架主要以JS+Native两者相互调用为主,从开发层面实现"一次开发,多处运行"的机制,成为真正适合跨平台的开发。 目前

h5+、mui等app安卓需要的Android权限大全(不用再费心找了)_mui videoplayer 勾选哪个权限_勇闯天亚的博客-程序员宅基地

1.android.permission.WRITE_USER_DICTIONARY  允许应用程序向用户词典中写入新词2.android.permission.WRITE_SYNC_SETTINGS  写入Google在线同步设置3.android.permission.WRITE_SOCIAL_STREAM  读取用户的社交信息流4.android.permission.WRITE_S...

推荐文章

热门文章

相关标签