快速排序 数组 单链表

来源:互联网 发布:闲鱼淘宝介入提交凭证 编辑:程序博客网 时间:2024/05/17 01:29

数组快速排序

快排注意知识点:

  • 每一趟排序,都有一个元素会放到其最终的位置上
  • 快排是个不稳定的算法
  • 最好情况 最坏情况的区别
    –运行时间 与 划分的区间是否对称 相关
    最好, 时间复杂度 O(nlog2n)
    最坏, 时间复杂度 O(n^2)

下面是参考严版教材的快排,可以敲上n遍了,debug运行 看每一步的结果

#include <stdio.h>int a[50] = { 21, 25, 5, 17, 9, 23, 30, 0, 25, 21 };int partion(int low, int high) {    // 一趟排序    int pivot = a[low];    while (low < high)    {        while (low < high && a[high] >= pivot)            --high;        a[low] = a[high];        while (low < high && a[low] < pivot)            ++low;        a[high] = a[low];    }    a[low] = pivot;  // 此时low 就是pivot 最终的位置    return low; // 返回最终确定的位置}void myqsort(int low, int high){    if (low >= high)        return ;    int left = low;    int right = high;    // 一趟排序    int pivot = a[low];    while (low < high)    {        // 从右往左 找到第一个小于pivot的 进行交换        while (low < high && a[high] >= pivot)             --high;        a[low] = a[high];        // 从左往右 找到第一个大于等于pivot的 进行交换        while (low < high && a[low] < pivot)            ++low;        a[high] = a[low];    }    a[low] = pivot;  // 此时low 就是pivot 最终的位置    // 下面递归    myqsort(left, low - 1);    myqsort(low + 1, right);}void pf(int n){    int i;    for (i = 0; i < n; i++)    {        printf("%d ", a[i]);    }    printf("\n");}int main(){    int n = 10;    myqsort(0, n-1);    pf(n);    return 0;}

单链表快速排序

leetcode上面用来检测自己的代码正确性,时空复杂度
https://leetcode.com/problems/insertion-sort-list/


参考
http://www.jb51.net/article/37300.htm

http://blog.csdn.net/wumuzi520/article/details/8078322

代码总结
partion 思路

  1. 支点的选取,由于不能随机访问第K个元素,因此每次选择支点时可以取待排序那部分链表的头指针。
  2. 遍历量表方式,由于不能从单链表的末尾向前遍历,因此使用两个指针分别向前向后遍历的策略实效,
    事实上,可以可以采用一趟遍历的方式将较小的元素放到单链表的左边。具体方法为:
    • 定义两个指针pslow,pfast,其中pslow指向单链表的头结点,pfast指向单链表头结点的下一个结点;
    • 使用pfast遍历单链表,每遇到一个比支点小的元素,就先令pslow=pslow->next,然后pslow与pfast进行数据交换。
  3. 交换数据方式,直接交换链表数据指针指向的部分,不必交换链表节点本身。
struct ListNode {    int val;    ListNode *next;    ListNode(int x) : val(x), next(NULL) {}};/*1、支点的选取,由于不能随机访问第K个元素,因此每次选择支点时可以取待排序那部分链表的头指针。2、遍历量表方式,由于不能从单链表的末尾向前遍历,因此使用两个指针分别向前向后遍历的策略实效,事实上,可以可以采用一趟遍历的方式将较小的元素放到单链表的左边。具体方法为:1)定义两个指针pslow,pfast,其中pslow指向单链表的头结点,pfast指向单链表头结点的下一个结点;2)使用pfast遍历单链表,每遇到一个比支点小的元素,就令pslow=pslow->next,然后和pslow进行数据交换。3、交换数据方式,直接交换链表数据指针指向的部分,不必交换链表节点本身。*/ListNode* partion(ListNode* head, ListNode* end){    if (head == end)        return head;    ListNode* pHead = head;    ListNode* pSlow = head; // pSlow和pSlow之前的都要小于等于pHead    ListNode* pFast = head->next;    while (pFast != end)    {        if (pFast->val < pHead->val)        {            pSlow = pSlow->next;// pSlow 先向后移动            int tmpVal = pFast->val; //交换pSlow和pFast的值            pFast->val = pSlow->val;            pSlow->val = tmpVal;        }        pFast = pFast->next;    }    int tmpVal = pSlow->val; // 最后与头节点交换    pSlow->val = pHead->val;    pHead->val = tmpVal;    return pSlow;}void qsortList(ListNode* head,ListNode* end){    if (head == NULL || head == end || head->next == end)        return;    ListNode* mid = partion(head, end);    qsortList(head, mid);    qsortList(mid->next, end);}int main(){    ListNode* p1 = new ListNode(4);    ListNode* p2 = new ListNode(2);    ListNode* p3 = new ListNode(5);    ListNode* p4 = new ListNode(3);    ListNode* p5 = new ListNode(7);    ListNode* p6 = new ListNode(9);    ListNode* p7 = new ListNode(0);    ListNode* p8 = new ListNode(1);    p1->next = p2;    p2->next = p3;    p3->next = p4;    p4->next = p5;    p5->next = p6;    p6->next = p7;    p7->next = p8;    //partion(p1, NULL);    qsortList(p1, NULL);}

交换节点,但是复杂度会比较大,应为每次都要遍历重复的

struct ListNode {    int val;    ListNode *next;    ListNode(int x) : val(x), next(NULL) {}};ListNode* partion(ListNode* head, ListNode* end){    if (head == end || head->next == end)        return head;    ListNode* pHead = head;    ListNode* lpart = NULL;    ListNode* lend = NULL;    ListNode* rpart = NULL;    ListNode* rend = NULL;    ListNode* pScan = head->next;    while (pScan != end)    {        if (pScan->val < pHead->val)        {            if(lpart == NULL)            {                lpart = lend = pScan;            }else{                lend->next = pScan;                lend = lend->next;            }        }else{            if(rpart == NULL)            {                rpart = rend = pScan;            }else{                rend->next = pScan;                rend = rend->next;            }        }        pScan = pScan->next;    }    if(lend != NULL)        lend->next = NULL;    if(rend != NULL)        rend->next = NULL;    // 按照左部分,partion节点,右部分再次连接成新的链表    ListNode* le = partion(lpart,NULL);     ListNode* re = partion(rpart,NULL);    ListNode *newHead = pHead;    if(le != NULL){        newHead = le;        ListNode* leTail = le; //找到le的尾节点        ListNode* letmp = le;        while(letmp != NULL){            leTail = letmp;            letmp  = letmp->next;        }        leTail->next = pHead;    }    pHead->next = re;    return newHead;}int main(){    ListNode* p1 = new ListNode(4);    ListNode* p2 = new ListNode(2);    ListNode* p3 = new ListNode(5);    ListNode* p4 = new ListNode(3);    ListNode* p5 = new ListNode(7);    ListNode* p6 = new ListNode(9);    ListNode* p7 = new ListNode(0);    ListNode* p8 = new ListNode(1);    p1->next = p2;    p2->next = p3;    p3->next = p4;    p4->next = p5;    p5->next = p6;    p6->next = p7;    p7->next = p8;    ListNode * pp = partion(p1, NULL);    return 0;}
0 0