单链表的快速排序(转)

单链表的特点是:单向。设头结点位head,则最后一个节点的next指向NULL。如果只知道头结点head,请问怎么将该链表排序?

设结点结构为

struct Node{
    int key;
    Node* next;
}; 

那么一般人见到这种题目,立马就会想到指针交换。是的,大家被指针交换的题目做多了,形成思维定势了。对于这道题,我们完全可以利用值交换来达到排序的目的。

当然,怎么值交换?

很多人得第一想法就是选择排序,这个木有问题,不过它的复杂度为O(n^2);有木有更好一点的方法呢?归并,不错,归并确实能将复杂度降到O(nlogn)不过,它是是链表交换的形式,我们这里提到的是要用值交换的形式。还有别的方法吗?对了,快排!

你可能回诧异,怎么会是快排?快排不是需要一个指针指向头,一个指针指向尾,然后两个指针相向运动并按一定规律交换值,最后找到一个支点使得支点左边小于支点,支点右边大于支点吗(这句话很长,累死俺了)?是滴,木有错,不过问题出来了。如果是这样的话,对于单链表我们没有前驱指针,怎么能使得后面的那个指针往前移动呢?所以这种快排思路行不通滴,如果我们能使两个指针都往next方向移动并且能找到支点那就好了。怎么做呢?

接下来我们使用快排的另一种思路来解答。我们只需要两个指针p和q,这两个指针均往next方向移动,移动的过程中保持p之前的key都小于选定的key,p和q之间的key都大于选定的key,那么当q走到末尾的时候便完成了一次支点的寻找。如下图所示:

既然两个指针都是从前往后遍历,那么链表值进行交换就简单了。找到支点后,支点左边和支点右边进行子问题递归,就回到快排原来的思路上去了。代码如下:

struct Node
{
    int key;
    Node* next;
    Node(int nKey, Node* pNext)
        : key(nKey)
        , next(pNext)
    {}
};  

Node* GetPartion(Node* pBegin, Node* pEnd)
{
    int key = pBegin->key;
    Node* p = pBegin;
    Node* q = p->next;  

    while(q != pEnd)
    {
        if(q->key < key)
        {
            p = p->next;
            swap(p->key,q->key);
        }  

        q = q->next;
    }
    swap(p->key,pBegin->key);
    return p;
}  

void QuickSort(Node* pBeign, Node* pEnd)
{
    if(pBeign != pEnd)
    {
        Node* partion = GetPartion(pBeign,pEnd);
        QuickSort(pBeign,partion);
        QuickSort(partion->next,pEnd);
    }
}  

使用时只需调用QuickSort(pHead,NULL)即可!

转自:https://blog.csdn.net/otuhacker/article/details/10366563

原文地址:https://www.cnblogs.com/zl1991/p/9665535.html

时间: 2024-10-17 00:23:52

单链表的快速排序(转)的相关文章

Java实现单链表的快速排序和归并排序

本文描述了LeetCode 148题 sort-list 的解法. 题目描述如下: Sort a linked list in O(n log n) time using constant space complexity. 题目要求我们在O(n log n)时间复杂度下完成对单链表的排序,我们知道平均时间复杂度为O(n log n)的排序方法有快速排序.归并排序和堆排序.而一般是用数组来实现二叉堆,当然可以用二叉树来实现,但是这么做太麻烦,还得花费额外的空间构建二叉树,于是不采用堆排序. 故本

单链表排序——快速排序实现

利用快速排序,同向一前一后两个指针 #ifndef LIST_H_ #define LIST_H_ #include <iostream> #include <utility> class List { private: struct ListNode { int _value; ListNode* _next; }; public: List(): _head(nullptr) {} ~List() { while (nullptr != _head) { auto tmp =

写给自己看的单链表(4):快速排序

搬运自我的CSDN https://blog.csdn.net/u013213111/article/details/88670136 !!!Attention:以下操作中的单链表均带有头结点!!!参考了这三篇文章:单链表快速排序算法的实现单链表的快速排序单链表的快排实现快速排序的思路是:首先,选取一个pivot:然后以pivot作为基准,对待排序的数据进行分区,得到两个部分,一个部分的数据均小于pivot,另一个部分的数据均大于pivot,然后对这两个部分再进行之前的操作,直至排序完成.对数组

单链表快速排序

根据普通快排的思路,选择1个点为中心点,保证中心点左边比中心点小,中心点右边比中心点大即可. 单链表的实现为: 1.使第一个节点为中心点. 2.创建2个指针(p,q),p指向头结点,q指向p的下一个节点. 3.q开始遍历,如果发现q的值比中心点的值小,则此时p=p->next,并且执行当前p的值和q的值交换,q遍历到链表尾即可. 4.把头结点的值和p的值执行交换.此时p节点为中心点,并且完成1轮快排 5.使用递归的方法即可完成排序 #include<iostream> #include

单链表的排序 快速排序 归并排序 quicksort mergesort

原理都很简单,关键是某些边界能否正确写对: #include<iostream> #include<stdio.h> using namespace std; class Node { public: int val; Node* next; Node(int val = 0):val(val),next(NULL){ } }; Node* quicksort(Node* head, Node* tail) { Node *res1 = NULL, *res2 = NULL; No

快速排序,归并排序,堆排序的数组和单链表实现

原文链接:https://www.cnblogs.com/DarrenChan/p/8807112.html 这三个排序的时间复杂度都是O(nlogn),所以这里放到一起说. 回到顶部 1. 快速排序# 快速排序(英语:Quicksort),又称划分交换排序(partition-exchange sort),通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成

148. Sort List (java 给单链表排序)

题目:Sort a linked list in O(n log n) time using constant space complexity. 分析:给单链表排序,要求时间复杂度是O(nlogn),空间复杂度是O(1).时间复杂度为O(nlogn)的排序算法有快速排序和归并排序, 但是,对于单链表来说,进行元素之间的交换比较复杂,但是连接两个有序链表相对简单,因此这里采用归并排序的思路. 编码: public ListNode sortList(ListNode head) { if(hea

数据结构与算法系列(1)-单链表类的实现(C++)

通过定义一个C++类封装单链表这种数据结构, 封装的方法有: 1.通过输入创建单链表: 2.获取单链表的数据元素个数: 3.打印输出单链表中各个元素: 4.搜索某个元素在单链表中的位置: 5.在某个位置之后插入一个结点: 6.在某个位置删除一个节点: 7.单链表逆置: 8.单链表是否存在回环的判定: 9.单链表的升序排序: 10.两个单链表的升序合并: 11.两个单链表的降序合并. 注:单链表的排序采用的是快速排序的方法. 下面是C++写的程序代码,附运行截图. #include <iostre

单链表(增、删、查找)

     用结构体构建单链表,实现单链表的基本功能. //头文件 #pragma once #include<stdio.h> #include<assert.h> #include<malloc.h> typedef int DataType; typedef struct ListNode { DataType _data; struct ListNode *_next; }ListNode; //初始化 void InitList(ListNode **ppHea