快速排序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; //负责把中枢纽的元素,插入到我们自己划分的little和big两个链表中间,此负责上部分,即little和pivot之间的连接 low->next = node2.next; //同上,负责big链表和pivot之间的连接 lowPre->next = node1.next;//为了保证子链表[low,high)和前面的部分连接 return low; } };
这个方法中little和big所组成的两个不同链表是有头节点的,分别是node1,和node2.
快速排序2(算法交换链表节点,平均时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))
这里的partition,我们选取第一个节点作为枢纽元,然后把小于枢纽的节点放到一个链中,把不小于枢纽的及节点放到另一个链中,最后把两条链以及枢纽连接成一条链。
这里我们需要注意的是:
1.在对一条子链进行partition时,由于节点的顺序都打乱了,所以得保正重新组合成一条新链表时,要和该子链表的前后部分连接起来,因此我们的partition传入三个参数,除了子链表的范围(也是前闭后开区间),还要传入子链表头结点的前驱;,由于本身就是前闭后开[ )所以,只需要传入prev,不需要传入high。因为本身就有
2.partition后链表的头结点可能已经改变,通过head的前驱,tmpHead(也可以用引用)