*LeetCode-148.Sort List(链表排序)
Sort a linked list in O(n log n) time using constant space complexity.
对链表排序,要达到 O(n log n)的时间复杂度,可使用归并排序
过程分为两部分:1.递归的进行排序; 2. 合并
有一个问题:怎么找链表的中点? 采用快慢指针的方法。快指针一次移动两个位置,慢指针一次移动1个位置。 当快指针或快指针的下一位指向空时,慢指针就指向中间。
将前后两段链表断开,然后分别对 head开始到slow 和slow.next开始到最后的两个链表进行排序,然后合并
//对链表进行排序,采用归并排序 public static ListNode sortList(ListNode head) { if(head == null||head.next == null) return head; ListNode fast = head.next; //注意fast初始就要比slow快,因为后半部分是从slow.next开始的,而不是slow ListNode slow = head; while(fast!=null && fast.next != null){ fast = fast.next.next; slow = slow.next; } ListNode sh = sortList(slow.next); slow.next = null; return merge(sortList(head),sh); } //将两部分合并 public static ListNode merge(ListNode h1, ListNode h2) { //合并两个部分 ListNode head = new ListNode(0); ListNode p = head; while(h1!=null&&h2!=null){ if(h1.val<h2.val){ p.next = h1; h1 = h1.next; }else{ p.next = h2; h2 = h2.next; } p = p.next; } if(h1!=null){ p.next = h1; } if(h2!=null){ p.next = h2; } return head.next; }
补充
(算法课堂作业:)
归并-最长无逆序子序列划分-链表-无递归
/*归并排序 划分时按最长无逆序子序列 链表实现 无递归*/ #include<iostream> #include<cstdio> #include<cstdlib> using namespace std; typedef struct Node{ //带头结点的链表 int data; struct Node* next; } LNode, *Linklist; //划分函数,获得一个有序的序列 void Mdivide(Linklist kaishi,LNode* &st,LNode* &en){ //st指向第一个 en指向最后一个 LNode *p=kaishi; //移动的指针 if(kaishi!=NULL){ st=kaishi; en=kaishi; } else{ //如果开始点就为空,则这部分的起始与结束均为空 st=NULL;en=NULL; return; } p=kaishi->next; while(p!=NULL&&(p->data>=en->data)){ //寻找无逆序子序列的结束点 en=p; p=p->next; } } //Merge函数将两个有序部分合并 void Merge(LNode* &pre,LNode* st1,LNode* en1,LNode* st2,LNode* en2 ){ LNode temp ; LNode t_en1,t_en2; //停止标记 t_en1.next=en1->next; // t_en2.next=en2->next; // temp.next=en2->next; //临时存放第二组的结束节点,就是下组要合并的pre指针 while(st1!=t_en1.next && st2!=t_en2.next){ if(st1->data < st2->data){ pre->next = st1; pre=pre->next; st1 = st1->next; }else{ pre->next = st2; pre=pre->next; st2 = st2->next; } } while(st1!=t_en1.next){ //合并剩余部分 pre->next=st1; pre=pre->next; st1=st1->next; } while(st2!=t_en2.next){ //合并剩余部分 pre->next=st2; pre=pre->next; st2=st2->next; } pre->next=temp.next; //与后面的节点连接 } //排序函数 void Mergesort(Linklist l ){ LNode *st1, *en1, *st2, *en2; LNode *templ; //指向每一部分的开始 LNode *pre; int flag=0; while(flag!=1){ //结束条件 templ = l->next; pre = l; //指向头指针(带头结点) while(pre->next!=NULL){ templ=pre->next; Mdivide(templ,st1,en1);//获得第一个划分 if(templ==l->next&&en1->next==NULL){ //如果本次划分开始前节点为首节点,尾结点的next为空,结束排序 flag=1;break; } templ=en1->next; //指向第二部分的开始 Mdivide(templ,st2,en2);//获得第二个部分 //对两种不同的划分状况进行不同方式的合并 if(st1!=NULL&&st2!=NULL){ //有两组无逆序子序列 Merge(pre,st1,en1,st2,en2); }else {//只有一组无逆序子序列 break; } } } } int main(){ Linklist l; //创建并初始化链表 // int num[]={1,2,3,4,5,6,7,8,9}; int num[] = {34,5, 20, 7,2,1, 8, 17,19,11,90,18, 28}; int i; l = (LNode*)malloc(sizeof(struct Node)); LNode* p = l; for(i=0;i<sizeof(num)/sizeof(int);i++){ LNode* n = (LNode*)malloc(sizeof(Node)); n->next = NULL; n->data = num[i]; p->next = n; p = n; } //打印初始链表 LNode *pri=l->next; while(pri!=NULL){ cout<<pri->data<<endl; pri=pri->next; } cout<<"原始元素输出完毕!"<<endl; Mergesort(l); //归并排序 cout<<"输出排序后的元素"<<endl; pri=l->next; while(pri!=NULL){ cout<<pri->data<<endl; pri=pri->next; } return 0 ; }

浙公网安备 33010602011771号