链表快速排序quick-sort(递归+迭代)

2023-05-16

递归版

直接上代码。

static void list_qsort(struct list_head *head)
{
    struct list_head list_less, list_greater;
    struct listitem *pivot;
    struct listitem *item = NULL, *is = NULL;

    if (list_empty(head) || list_is_singular(head))
        return;

    INIT_LIST_HEAD(&list_less);
    INIT_LIST_HEAD(&list_greater);

	//取出第一个节点
    pivot = list_first_entry(head, struct listitem, list);
	//从原链表中删除
    list_del(&pivot->list);

	// item用于遍历, is内部使用的临时变量
    list_for_each_entry_safe (item, is, head, list) {
        if (cmpint(&item->i, &pivot->i) < 0)
            list_move_tail(&item->list, &list_less);
        else
            list_move(&item->list, &list_greater);
    }

    list_qsort(&list_less);
    list_qsort(&list_greater);

    list_add(&pivot->list, head);
    list_splice(&list_less, head);
    list_splice_tail(&list_greater, head);
}


list_add / list_add_tail
将指定的 node 插入 linked list head 的

先将list节点从原链表中删除,然后将这个节点,添加到后边链表的开头/结尾
list_move / list_move_tail

list_splice / list_splice_tail(struct list_head *list, struct list_head *head) (splice拼接)
将 list 的所有 node 都插入到 head 的开头/结尾。注意 list 链表本身仍维持原貌。

 
 

非递归版

原文地址:
https://alienryderflex.com/quicksort/

这篇文章实在太吊了,现简单陈列如下,作者比较了两种版本的实现。
流传甚广的维基百科版:

void swap(int *a, int *b)
{
  int t=*a; *a=*b; *b=t;
}
void sort(int arr[], int beg, int end)
{
  if (end > beg + 1)
  {
    int piv = arr[beg], l = beg + 1, r = end;
    while (l < r)
    {
      if (arr[l] <= piv)
        l++;
      else
        swap(&arr[l], &arr[--r]);
    }
    swap(&arr[--l], &arr[beg]);
    sort(arr, beg, l);
    sort(arr, r, end);
  }
}
作者说,把swap加上inline关键字,可以减少调用函数的栈开支。

作者自己的版本:

//  quickSort
//
//  This public-domain C implementation by Darel Rex Finley.
//
//  * Returns YES if sort was successful, or NO if the nested
//    pivots went too deep, in which case your array will have
//    been re-ordered, but probably not sorted correctly.
//
//  * This function assumes it is called with valid parameters.
//
//  * Example calls:
//    quickSort(&myArray[0],5); // sorts elements 0, 1, 2, 3, and 4
//    quickSort(&myArray[3],5); // sorts elements 3, 4, 5, 6, and 7

bool quickSort(int *arr, int elements) {

  #define  MAX_LEVELS  1000

  int  piv, beg[MAX_LEVELS], end[MAX_LEVELS], i=0, L, R ;

  beg[0]=0; end[0]=elements;
  while (i>=0) {
    L=beg[i]; R=end[i]-1;
    if (L<R) {
      piv=arr[L]; if (i==MAX_LEVELS-1) return NO;
      while (L<R) {
        while (arr[R]>=piv && L<R) R--; if (L<R) arr[L++]=arr[R];
        while (arr[L]<=piv && L<R) L++; if (L<R) arr[R--]=arr[L]; }
      arr[L]=piv; beg[i+1]=L+1; end[i+1]=end[i]; end[i++]=L; }
    else {
      i--; }}
  return YES; }

Advantages of my code over the Wikipedia code: 优势

  1. FUNCTION CALLS My implementation avoids function calls. Calling (and returning from) a function is time-consuming, and not because the content of the function takes time to execute — just getting into the function, and back out of it, uses processor time.

  2. STACK My implementation does not use the stack to store data. Recursive functions look neat and simple in part because they don’t have to have big arrays like my beg[] and end[]. But all they’re really doing is using the stack as their own private array. This is much slower than using a real array, and could cause stack overflow on some systems, crashing the app that called the quicksort. My implementation simply returns NO if this kind of failure occurs.

  3. SWAP VARIABLE In any one pivot round, the Wikipedia version can pass items through a swap variable many times. My code passes only one item (the pivot) through a swap variable, and only once per round.

  4. MULTIPLE MOVES In any one pivot round, the Wikipedia version can move the same item more than once in the list. My code never moves an item to a new position in the list more than once per round.

  5. UNNECESSARY MOVES In any one pivot round, the Wikipedia version will sometimes move items to new positions in the list even though they were already on the correct side of where the pivot item was going to wind up. My code never moves an item if its current position is on the correct side of the pivot’s destination.

  6. SELF-SWAPS In each pivot round, the Wikipedia version has about a 50% chance of swapping one of the list items with itself. (And this swap incurs the costs described above in #1, #2, and #3.)

(Note that the benefits of all six advantages are greatly increased if the items being sorted are substantially sized data structures, as opposed to simple integers as in these code examples.)

Limitations of my code vs. the Wiki code:劣势

  1. COMPARISONS My code performs more comparisons, on average, than the Wiki version. Wiki does 30% fewer comparisons by my (very rough) estimate.

 
 
非常给力的图示来了,
作者自己的版本:
在这里插入图片描述
数字 3, 8, 7 没有动位置. 其他数字只移动了一次,而且和 pivot(支点) 只比较了一次。
维基百科版:
在这里插入图片描述
在数据值3、8和7中(它们都不需要移动的),只有3没动,8被移动了两次。Swap 变量被使用了五次。

 
 
最后作者又来了一个无敌版,从来不会失败的版本(永远都不会跑到 MAX_LEVELS ):

//  quickSort
//
//  This public-domain C implementation by Darel Rex Finley.
//
//  * This function assumes it is called with valid parameters.
//
//  * Example calls:
//    quickSort(&myArray[0],5); // sorts elements 0, 1, 2, 3, and 4
//    quickSort(&myArray[3],5); // sorts elements 3, 4, 5, 6, and 7

void quickSort(int *arr, int elements) {

  #define  MAX_LEVELS  300

  int  piv, beg[MAX_LEVELS], end[MAX_LEVELS], i=0, L, R, swap ;

  beg[0]=0; end[0]=elements;
  while (i>=0) {
    L=beg[i]; R=end[i]-1;
    if (L<R) {
      piv=arr[L];
      while (L<R) {
        while (arr[R]>=piv && L<R) R--; if (L<R) arr[L++]=arr[R];
        while (arr[L]<=piv && L<R) L++; if (L<R) arr[R--]=arr[L]; }
      arr[L]=piv; beg[i+1]=L+1; end[i+1]=end[i]; end[i++]=L;
      if (end[i]-beg[i]>end[i-1]-beg[i-1]) {
        swap=beg[i]; beg[i]=beg[i-1]; beg[i-1]=swap;
        swap=end[i]; end[i]=end[i-1]; end[i-1]=swap; }}
    else {
      i--; }}}

This might be slightly slower than the first one, but it will never fail because it always performs the smaller partition first. Hence, the only way it could run into the limit is if the to-be-sorted array was at least 2^MAX_LEVELS elements in size. Since 2^300 is greater than 10^90, and there are only about 1080 fundamental particles in this universe from which a human-made computer can be built, no larger limit will ever be needed.

(Note: Someone reminded me that a typically 64-bit index variable can index only 2^64 items, not 2^300. That’s true, but if you’re using a 64-bit computer, you’re probably not going to have an array of more than 2^64 elements anyway, even if each element was only one byte.)

------------------回到我们讨论的非递归版本的快速排序----------------------
直接看代码:

static void list_qsort_no_recursive(struct list_head *head) {
    struct listitem *begin[MAX_LEN], *end[MAX_LEN], *L, *R;
    struct listitem pivot;
    int i = 0;

    begin[0] = list_first_entry(head, struct listitem, list);
    end[0] = list_last_entry(head, struct listitem, list);
    while (i >= 0) {
        L = begin[i];
        R = end[i];
        if (L != R && &begin[i]->list != head) {
            // pivot is the actual address of L
            pivot = *begin[i];
            if (i == MAX_LEN - 1) {
                assert(-1);
                return;
            }
            while (L != R) {
                while (R->i >= pivot.i && L != R)
                    R = list_entry(R->list.prev, struct listitem, list);
                if (L != R) {
                    L->i = R->i;
                    L = list_entry(L->list.next, struct listitem, list);
                }

                while (L->i <= pivot.i && L != R)
                    L = list_entry(L->list.next, struct listitem, list);
                if (L != R) {
                    R->i = L->i;
                    R = list_entry(R->list.prev, struct listitem, list);
                }
            }
            L->i = pivot.i;
            begin[i + 1] = list_entry(L->list.next, struct listitem, list);
            end[i + 1] = end[i];
            end[i++] = L;
        } else
            i--;
    }
}

 
 
完。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

链表快速排序quick-sort(递归+迭代) 的相关文章

  • python不用sort排序_python排序sort()与sorted()

    应用举例 xff1a 1 按照字母表输出一个序列 2 对记录的多个字段排序等 常用排序函数 xff1a sort sorted 比较 xff1a 1 sorted 应用范围更广 sorted iterable cmp key reverse
  • 二维数组快速排序sort

    二维数组快速排序sort 1 使用比较函数cmp2 使用lambda表达式 使用c 43 43 的快排函数需要包含头文件 include lt algorithm gt 1 使用比较函数cmp span class token macro
  • 排序 —— 选择排序(Selection sort)

    简介 选择排序是一种直观的排序 xff0c 但是不稳定的排序方法 一 思路 首先在未排序序列中找到最小或最小元素 xff0c 存放到排序序列的起始位置 xff0c 然后 xff0c 再从剩余未排序元素中继续寻找最小或最大元素 xff0c 然
  • C++ sort()函数cmp的含义

    头文件 xff1a include lt algorithm gt std sort first last cmp 使用的范围是 first last 省略 cmp xff0c 使用 sort first last 则默认从 小到大排序 使
  • STL std::sort 源码分析

    转载自http feihu me blog 2014 sgi std sort 最近在看sort源码 xff0c 看到这篇博文很好 xff0c 转发作为记录 xff0c 转载侵权联系我删除 背景 在校期间 xff0c 为了掌握这些排序算法
  • 自定义 Qt Quick Controls

    自定义 Qt Quick Controls 使用 Qt Quick 编写界面时 xff0c 使用 Qt Quick Controls xff08 指Qt Quick Controls 2 xff09 模块中提供的大量控件 xff0c 可以快
  • 数据结构实验之排序三:bucket sort

    数据结构实验之排序三 xff1a bucket sort 作为桶排序的典型例题 xff0c 我们完全可以按照桶排序的思想来做这个题 但是本题完全不需要用太多的空间去换时间 xff0c 只需要一个空间为101的一维数组就好 Problem D
  • Insertion Sort List

    Sort a linked list using insertion sort 对一个线性链表排序 xff0c 维护两对指针即可 ListNode insertionSortList ListNode head if head return
  • C++ vector数组实现多级排序—使用sort()函数

    之前有记录过 python 使用 numpy 的多级排序方法 xff1a numpy 多级排序 xff1a lexsort 函数详解 地球被支点撬走啦的博客 CSDN博客 lexsort C 43 43 多级排序可以借用 sort 函数 x
  • Qt Quick 3D系列(三):设置三维模型的金属光泽材质

    前面的博客中介绍了如何在Qt Quick 3D中加载三维模型 xff0c 下面介绍如何设置三维模型的材质 xff0c 例如下图模型 我需要设置为金属材质时 xff0c 设置该Model的materials为PrincipledMateria
  • 【leetcode】1122. 数组的相对排序(relative-sort-array)(模拟)[简单]

    链接 https leetcode cn com problems relative sort array 耗时 解题 xff1a 12 min 题解 xff1a 12 min 题意 给你两个数组 xff0c arr1 和 arr2 xff
  • python中sort和sorted的高级排序技巧

    Python list内置sort 方法用来排序 xff0c 也可以用python内置的全局sorted 方法来对可迭代的序列排序生成新的序列 1 排序基础 简单的升序排序是非常容易的 只需要调用sorted 方法 它返回一个新的list
  • C++中的qsort、sort排序

    注意 xff1a int char string之类的是可以之间使用 gt lt 61 61 之类的进行判断 xff0c char 类型的使用strcmp就行了 而struct与vector都可以当做数组进行处理 xff0c cmp函数传递
  • quick sort(c++)以及k选取

    include lt iostream gt include lt vector gt using rank 61 int using namespace std int dash 61 0 int swap vector lt int g
  • Qt Quick 之 QML 与 C++ 混合编程详解

    Qt Quick 技术的引入 xff0c 使得你能够快速构建 UI xff0c 具有动画 各种绚丽效果的 UI 都不在话下 但它不是万能的 xff0c 也有很多局限性 xff0c 原来 Qt 的一些技术 xff0c 比如低阶的网络编程如 Q
  • Quick - Hello World

    文章目录 背景 谈一谈为我什么学QtQuick 环境搭建 Qt 安装 VS2019 安装 Qt Visual Studio Tools Hello World pro main cpp main qml 运行效果 参考鸣谢 背景 Qt4自2
  • 信息学奥赛一本通 1176:谁考了第k名

    题目链接 http ybt ssoier cn 8088 problem show php pid 1176 include
  • 【Shell牛客刷题系列】SHELL9 统计每个单词出现的个数:一起学习sort排序命令和uniq去重命令

    该系列是基于牛客Shell题库 针对具体题目进行查漏补缺 学习相应的命令 刷题链接 牛客题霸 Shell篇 该系列文章都放到专栏下 专栏链接为 专栏 Linux 欢迎关注专栏 本文知识预告 首先学习了对文件内容进行排序的sort命令和去除文
  • R语言排序函数sort(),rank(),order()

    转载地址 http blog sina com cn s blog 6caea8bf0100spe9 html 在R中 和排序相关的函数主要有三个 sort rank order sort x 是对向量x进行排序 返回值排序后的数值向量 r
  • 信息学奥赛一本通 1182:合影效果

    题目链接 http ybt ssoier cn 8088 problem show php pid 1182 include

随机推荐

  • Android 10编译报错整理

    编译Android 10遇到以下不同报错 xff0c 没有给出明显的错误信息 xff0c 最后验证出是电脑内存不足导致编译被杀掉 xff0c 增大电脑内存和Swap分区之后解决 注 有关详细信息 请使用 Xlint unchecked 重新
  • vcpkg快速使用教程

    vcpkg是一个自动管理开源库的工具 xff0c 你可以把它想像成Ubuntu的apt get软件包 自动下载开源软件包软件包可以升级版本或补丁包自动编译软件包软件包依赖的包自动检查下载编译可集成至Visual Studio xff0c 你
  • 生产者消费者问题(Producer:1、Consumer:1、Buffer:1)

    生产者消费者问题是一个著名的线程同步问题 xff0c 该问题描述如下 xff1a 有一个生产者在生产产品 xff0c 这些产品将提供给若干个消费者去消费 xff0c 为了使生产者和消费者能并发执行 xff0c 在两者之间设置一个具有多个缓冲
  • (ROS)差分轮式机械臂机器人(二)六轴机械臂Moveit配置&深度相机kinect配置

    上一次搭建出了差分式移动底盘和六轴机械臂 这一次总结机械臂的Moveit配置和底盘kinect深度相机配置 文章目录 项目源码机械臂Moveit配置Moveit具体是什么可以参考 古月居的视频教程 https www bilibili co
  • 操作系统--线程

    线程 什么是是线程 进程中的一条执行流程 线程的优点 一个进程可以同时存在多个线程各个线程之间并发执行各个线程之间共享地址空间和文件等资源 线程的缺点 一个线程崩溃将导致其余所有线程崩溃 线程所需的资源 进程与线程的比较 线程的实现 用户线
  • ros底盘驱动包存在scan跟不上车体运行的错误调试过程

    现象描述 一个和底盘通讯的代码和ros包 总是发现当控制车体运行一段距离 rviz里面scan的数据更新会过一秒才能跟着运动走 同时发现tf的base link也是过一秒才更新 调试过程 起初 以为是串口堵塞 没有及时的接受和处理底盘上行发
  • 变频器电路原理详解经典

    要想做好变频器维修 xff0c 当然了解变频器基础知识是相当重要的 xff0c 也是迫不及待的 下面我们就来分享一下变频器维修基础知识 大家看完后 xff0c 如果有不正确地方 xff0c 望您指正 xff0c 如果觉得还行支持一下 xff
  • UART模块验证-面试总结

    前言 本篇博客依旧针对UART模块的验证项目进行面试总结 xff0c 也是笔者面试过众多公司所总结整理的 关于UART深挖的可问的知识点还是非常多 xff0c 本篇博文可以说基本上涵盖大部分可问到的点 关于下列有一些问题我并没有列出答案 x
  • 你所不知道的C语言——链表内是否有环(龟兔赛跑算法)

    判断链表中是否有环 xff0c 这也是力扣的题 xff1a 141 Linked List Cycle 142 Linked List Cycle II 146 LRU缓存 不多比比 xff0c 直接上代码 xff1a 变量 mu 指的是
  • 古诗文本自动生成唐诗文本生成(算例代码)

    首先准备好一个本地文件 xff0c 在此我命名为唐诗三百首 txt如下图 https img blog csdnimg 图片 代码如下 span class token keyword import span numpy span clas
  • __attribute__ 你知多少?

    GNU C 的一大特色就是 attribute 机制 attribute 可以设置函数属性 xff08 Function Attribute xff09 变量属性 xff08 Variable Attribute xff09 和类型属性 x
  • ChatGPT被淘汰了?Auto-GPT到底有多强

    大家好 xff0c 我是可夫小子 xff0c 关注AIGC 读书和自媒体 解锁更多ChatGPT AI绘画玩法 说Auto GPT淘汰了ChatGPT了 xff0c 显然是营销文案里面的标题党 毕竟它还是基于ChatGPT的API xff0
  • Word+ChatGPT,一分钟完成周报总结作文

    大家好 xff0c 我是可夫小子 xff0c 关注AIGC 读书和自媒体 解锁更多ChatGPT AI绘画玩法 加 xff1a keeepdance xff0c 备注 xff1a chatgpt xff0c 拉你进群 Office 的办公软
  • 两分钟速览谷歌2023IO大会:AI军备竞争,全线出击

    大家好 xff0c 我是可夫小子 xff0c 关注AIGC 读书和自媒体 解锁更多ChatGPT AI绘画玩法 加 xff1a keeepdance xff0c 备注 xff1a chatgpt xff0c 拉你进群 5月10日周三 xff
  • 科大讯飞星火认知大模型:诚意满满、全村希望

    近日 xff0c 科大讯飞召开了星火认知大模型成果发布会 xff0c 会上表示讯飞星火大模型将突破开放式问答 xff0c 对标ChatGPT xff0c 在中文能力上超过ChatGPT xff0c 在英文能力上与ChatGPT相当 对此 x
  • Android NDK tombstone分析工具

    Android NDK tombstone分析工具 在Andoird Native库发生异常的时候 xff0c Linux会发生不同级别的sig xff0c 来结构相关进程的运行 xff0c 同时会产生tombstone trace文件用于
  • 关于UEFI

    最近在Thinkpad上安装Ubuntu12 04的时候 xff0c 经历了几个问题 xff0c 发现BOIS里多了很多选项 xff0c 而且安装双系统也有UEFI有关 xff0c 在网站上找了一篇文章 xff0c 发现这还是一个新概念 x
  • 怎样在github上协同开发

    描述 xff1a How to co work wither parter via github Github协同开发情景模拟 Github不仅有很多开源的项目可以参考 xff0c 同样也是协同开发的最佳工具 xff0c 接下来的就模拟一下
  • Android libdvm.so 与 libart.so

    Android libdvm so 与 libart so 系统升级到5 1之后 xff0c 发现system lib 下面没有libdvm so了 xff0c 只剩下了libart so 对于libart模式 xff0c 从4 4就在De
  • 链表快速排序quick-sort(递归+迭代)

    递归版 直接上代码 span class token keyword static span span class token keyword void span span class token function list qsort s