链表的归并排序

来源:互联网 发布:淘宝软妹衣服店 编辑:程序博客网 时间:2024/06/04 18:01

一开始写链表的排序代码是因为在《算法》里面看到说自低向上的归并算法比较适合链表结构的数据,但是里面没有给出代码,于是就自己拿来练手。

链表排序与数组排序最大的不同就是随机访问代价太高,每次都需要遍历。

归并的思想就是把大的数据分成小数据,先将小数据排序,然后再并起来。

而自低向上的归并,是一变二,二变四...最终变成一个整体(具体请参考算法书)

对于链表来说,两个小链表的合并与两个数组的合并没有太大区别,都是两边同时遍历进行比较然后取较小(大)值,形成一个大的有序序列。

不同是如何将大序列分成小序列,数组可以直接把下表均分,而链表则需要遍历一遍才能均分。

我看到网上的实现,好像也都是这么做的:

 《用归并排序对链表进行排序》

用归并排序对链表进行排序


其中的FrontBackSplit()函数就是用快慢指针进行遍历,然后分成2半。

不过每次分完之后链表的长度都会变小,所以其实花费的时间还是可以接受的。

然后我自己写了一个实现方法,是用队列保存各个小序列的头指针,从而避免每次找头指针的消耗。这是一开始看到题目时候的思路,但是现在回过头看,感觉为了节省这点时间额外增加了这么多的空间消耗(N/2长度的队列)似乎有点不值。不过还是把代码贴上来:

两个链表的合并我就直接用了上面那片文章里的函数了,写得非常简洁:

myNode* mergeForList(myNode* a, myNode* b){myNode* result = nullptr;if (a == nullptr)return(b);else if (b==nullptr)return(a);  /* 使用递归调用的方法 */ if (a->val <= b->val){     result = a;     result->next = mergeForList(a->next, b); } else   {     result = b;     result->next = mergeForList(a, b->next); } return(result);}

myNode定义:

class myNode{public :int val;myNode* next;};


归并排序的实现:

void mergeSort2ForList(myNode* &head)//链表的归并排序{if(head==nullptr) return;queue<myNode*> ptQueue;myNode *head1, *head2, *head3;head1=head;//先两两合并,如1和2合并,3和4合并,合并完把结尾指向空指针,并把头指针加入队列while(head1!=nullptr&&head1->next!=nullptr){head2=head1->next;head3=head2->next;if(head1->val <=head2->val){//如果小序列里的第一个节点比较小,那么不需要交换位置,直接把第一个节点作为头指针入队列,第二个节点指向空ptQueue.push(head1);head2->next=nullptr;}else{//如果第二个比较小,则交换位置ptQueue.push(head2);head2->next=head1;head1->next=nullptr;}head1=head3;}if(head1!=nullptr)//说明是单数个数据,把最后一个数据直接入队列ptQueue.push(head1);//开始两两合并队列里的序列,注意合并之后的新序列的头指针会继续入队列while(ptQueue.size()!=1){//合并后的长度越来越长,可合并的序列也越来越少//当合并的序列只有一个时,退出循环head1=ptQueue.front();//取出第一个序列ptQueue.pop();head2=ptQueue.front();//取第二个序列ptQueue.pop();ptQueue.push( mergeForList(head1, head2));//合并之后的新序列的头指针继续入队列}head=ptQueue.front();//排序后的头指针}





0 0
原创粉丝点击