• 链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)


    参考http://www.cnblogs.com/TenosDoIt/p/3666585.html

    插入排序(算法中是直接交换节点,时间复杂度O(n^2),空间复杂度O(1)

     1 class Solution {
     2 public:
     3     ListNode *insertionSortList(ListNode *head) {
     4         // IMPORTANT: Please reset any member data you declared, as
     5         // the same Solution instance will be reused for each test case.
     6         if(head == NULL || head->next == NULL)return head;
     7         ListNode *p = head->next, *pstart = new ListNode(0), *pend = head;
     8         pstart->next = head; //为了操作方便,添加一个头结点
     9         while(p != NULL)
    10         {
    11             ListNode *tmp = pstart->next, *pre = pstart;
    12             while(tmp != p && p->val >= tmp->val) //找到插入位置
    13                 {tmp = tmp->next; pre = pre->next;}
    14             if(tmp == p)pend = p;
    15             else
    16             {
    17                 pend->next = p->next;
    18                 p->next = tmp;
    19                 pre->next = p;
    20             }
    21             p = pend->next;
    22         }
    23         head = pstart->next;
    24         delete pstart;
    25         return head;
    26     }
    27 };

    选择排序(算法中只是交换节点的val值,时间复杂度O(n^2),空间复杂度O(1)

     1 class Solution {
     2 public:
     3     ListNode *selectSortList(ListNode *head) {
     4         // IMPORTANT: Please reset any member data you declared, as
     5         // the same Solution instance will be reused for each test case.
     6         //选择排序
     7         if(head == NULL || head->next == NULL)return head;
     8         ListNode *pstart = new ListNode(0);
     9         pstart->next = head; //为了操作方便,添加一个头结点
    10         ListNode*sortedTail = pstart;//指向已排好序的部分的尾部
    11         
    12         while(sortedTail->next != NULL)
    13         {
    14             ListNode*minNode = sortedTail->next, *p = sortedTail->next->next;
    15             //寻找未排序部分的最小节点
    16             while(p != NULL)
    17             {
    18                 if(p->val < minNode->val)
    19                     minNode = p;
    20                 p = p->next;
    21             }
    22             swap(minNode->val, sortedTail->next->val);
    23             sortedTail = sortedTail->next;
    24         }
    25         
    26         head = pstart->next;
    27         delete pstart;
    28         return head;
    29     }
    30 };

    快速排序1(算法只交换节点的val值,平均时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))

    这里的partition我们参考数组快排partition的第二种写法(选取第一个元素作为枢纽元的版本,因为链表选择最后一元素需要遍历一遍),具体可以参考here

    这里我们还需要注意的一点是数组的partition两个参数分别代表数组的起始位置,两边都是闭区间,这样在排序的主函数中:

    void quicksort(vector<int>&arr, int low, int high)

    {

      if(low < high)

      {

       int middle = mypartition(arr, low, high);

       quicksort(arr, low, middle-1);

       quicksort(arr, middle+1, high);

      }

    }

    对左边子数组排序时,子数组右边界是middle-1,如果链表也按这种两边都是闭区间的话,找到分割后枢纽元middle,找到middle-1还得再次遍历数组,因此链表的partition采用前闭后开的区间(这样排序主函数也需要前闭后开区间),这样就可以避免上述问题

     
     1 class Solution {
     2 public:
     3     ListNode *quickSortList(ListNode *head) {
     4         // IMPORTANT: Please reset any member data you declared, as
     5         // the same Solution instance will be reused for each test case.
     6         //链表快速排序
     7         if(head == NULL || head->next == NULL)return head;
     8         qsortList(head, NULL);
     9         return head;
    10     }
    11     void qsortList(ListNode*head, ListNode*tail)
    12     {
    13         //链表范围是[low, high)
    14         if(head != tail && head->next != tail)
    15         {
    16             ListNode* mid = partitionList(head, tail);
    17             qsortList(head, mid);
    18             qsortList(mid->next, tail);
    19         }
    20     }
    21     ListNode* partitionList(ListNode*low, ListNode*high)
    22     {
    23         //链表范围是[low, high)
    24         int key = low->val;
    25         ListNode* loc = low;
    26         for(ListNode*i = low->next; i != high; i = i->next)
    27             if(i->val < key)
    28             {
    29                 loc = loc->next;
    30                 swap(i->val, loc->val);
    31             }
    32         swap(loc->val, low->val);
    33         return loc;
    34     }
    35 };

    快速排序2(算法交换链表节点,平均时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))

    这里的partition,我们选取第一个节点作为枢纽元,然后把小于枢纽的节点放到一个链中,把不小于枢纽的及节点放到另一个链中,最后把两条链以及枢纽连接成一条链。

    这里我们需要注意的是,1.在对一条子链进行partition时,由于节点的顺序都打乱了,所以得保正重新组合成一条新链表时,要和该子链表的前后部分连接起来,因此我们的partition传入三个参数,除了子链表的范围(也是前闭后开区间),还要传入子链表头结点的前驱;2.partition后链表的头结点可能已经改变

    class Solution {
    public:
        ListNode *quickSortList(ListNode *head) {
            // IMPORTANT: Please reset any member data you declared, as
            // the same Solution instance will be reused for each test case.
            //链表快速排序
            if(head == NULL || head->next == NULL)return head;
            ListNode tmpHead(0); tmpHead.next = head;
            qsortList(&tmpHead, head, NULL);
            return tmpHead.next;
        }
        void qsortList(ListNode *headPre, ListNode*head, ListNode*tail)
        {
            //链表范围是[low, high)
            if(head != tail && head->next != tail)
            {
                ListNode* mid = partitionList(headPre, head, tail);//注意这里head可能不再指向链表头了
                qsortList(headPre, headPre->next, mid);
                qsortList(mid, mid->next, tail);
            }
        }
        ListNode* partitionList(ListNode* lowPre, ListNode* low, ListNode* high)
        {
            //链表范围是[low, high)
            int key = low->val;
            ListNode node1(0), node2(0);//比key小的链的头结点,比key大的链的头结点
            ListNode* little = &node1, *big = &node2;
            for(ListNode*i = low->next; i != high; i = i->next)
                if(i->val < key)
                {
                    little->next = i;
                    little = i;
                }
                else
                {
                    big->next = i;
                    big = i;
                }
            big->next = high;//保证子链表[low,high)和后面的部分连接
            little->next = low;
            low->next = node2.next;
            lowPre->next = node1.next;//为了保证子链表[low,high)和前面的部分连接
            return low;
        }
    };

    归并排序(算法交换链表节点,时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))                        本文地址

    首先用快慢指针的方法找到链表中间节点,然后递归的对两个子链表排序,把两个排好序的子链表合并成一条有序的链表。归并排序应该算是链表排序最佳的选择了,保证了最好和最坏时间复杂度都是nlogn,而且它在数组排序中广受诟病的空间复杂度在链表排序中也从O(n)降到了O(1)

    class Solution {
    public:
        ListNode *mergeSortList(ListNode *head) {
            // IMPORTANT: Please reset any member data you declared, as
            // the same Solution instance will be reused for each test case.
            //链表归并排序
            if(head == NULL || head->next == NULL)return head;
            else
            {
                //快慢指针找到中间节点
                ListNode *fast = head,*slow = head;
                while(fast->next != NULL && fast->next->next != NULL)
                {
                    fast = fast->next->next;
                    slow = slow->next;
                }
                fast = slow;
                slow = slow->next;
                fast->next = NULL;
                fast = sortList(head);//前半段排序
                slow = sortList(slow);//后半段排序
                return merge(fast,slow);
            }
             
        }
        // merge two sorted list to one
        ListNode *merge(ListNode *head1, ListNode *head2)
        {
            if(head1 == NULL)return head2;
            if(head2 == NULL)return head1;
            ListNode *res , *p ;
            if(head1->val < head2->val)
                {res = head1; head1 = head1->next;}
            else{res = head2; head2 = head2->next;}
            p = res;
             
            while(head1 != NULL && head2 != NULL)
            {
                if(head1->val < head2->val)
                {
                    p->next = head1;
                    head1 = head1->next;
                }
                else
                {
                    p->next = head2;
                    head2 = head2->next;
                }
                p = p->next;
            }
            if(head1 != NULL)p->next = head1;
            else if(head2 != NULL)p->next = head2;
            return res;
        }
    };

    冒泡排序(算法交换链表节点val值,时间复杂度O(n^2),空间复杂度O(1))

    class Solution {
    public:
        ListNode *bubbleSortList(ListNode *head) {
            // IMPORTANT: Please reset any member data you declared, as
            // the same Solution instance will be reused for each test case.
            //链表快速排序
            if(head == NULL || head->next == NULL)return head;
            ListNode *p = NULL;
            bool isChange = true;
            while(p != head->next && isChange)
            {
                ListNode *q = head;
                isChange = false;//标志当前这一轮中又没有发生元素交换,如果没有则表示数组已经有序
                for(; q->next && q->next != p; q = q->next)
                {
                    if(q->val > q->next->val)
                    {
                        swap(q->val, q->next->val);
                        isChange = true;
                    }
                }
                p = q;
            }
            return head;
        }
    };


  • 相关阅读:
    多线程
    Java命令行传参
    IO流
    集合
    Java基础语法
    常见的数据结构
    泛型
    java 集合重要概念 (Set 的存储内存解析)
    java 集合重要概念 (== 和 equals 解读)
    java 集合重要概念 (实现一个简单的斗地主)
  • 原文地址:https://www.cnblogs.com/StarZhai/p/9984230.html
Copyright © 2020-2023  润新知