手把手教你实现链表的归并排序

来源:互联网 发布:cocos2d 源码 编辑:程序博客网 时间:2024/06/05 08:33

参考资料:《数据结构与算法分析》(第三版英文版)

书本题目:7.20 (269页)

这个题目的意思很简单,就是实现链表的归并排序

先实现一个简单的节点Node结构

struct Node {int data;Node* next;Node(int val) {data = val;next = NULL;}Node(){data = 0;next = NULL;}};

再到链表

struct List {Node* head;Node* tail;List(int val){head = new Node(val);tail = head;}void append(int val){tail->next = new Node(val);tail = tail->next;}};
在main函数里面测试链表是否成功

int main() {List list = List(6);list.append(3);list.append(4);list.append(9);list.append(8);list.append(3);list.append(42);list.append(25);list.append(51);list.append(30);Node* test = list.head;for (int i = 0; i < 10; i++){cout << test->data << " ";test = test->next;}system("pause");}
运行程序,成功按顺序打印出数值


下面是链表归并函数的实现

Node* listMergeSort(Node* head) //传入需要归并排序的链表的头指针{ //一个元素就返回if (head->next == NULL)return head;//使用 slow-fast方法找到链表的中间位置,注意这里写的链表的头节点是非空的,即头节点也是存贮数据的Node* fast = head->next;  //   fast指向第2个节点Node* slow = head;  //   slow指向第1个节点while (fast != NULL&&fast->next != NULL){fast = fast->next->next; //fast每次走两步slow = slow->next;//slow每次走一步,这样slow就会到lian'biao中点}//slow最后指向有n个元素的链表的第n/2个元素。如一共6个元素,slow指向第3个,一共5个元素,slow指向第2个。Node* left = head;Node* right = slow->next;slow->next = NULL;//但是实际上将链表截断,左边的部分从第1个开始,右边的要从第4个(共6个)或者第3个(共5个)开始,所以有right=slow->next;//假设上面截断的左右两个子链表调用归并排序后变成了排好序(new,新)的“新”左右两个链表,然后开始归并Node* newLeft = listMergeSort(left);Node* newRight = listMergeSort(right);Node * newList ;  //注意指针tail才是后面进行操作的指针,newList是为了保存起点Node * tail ;if (newLeft->data < newRight->data){newList = newLeft;newLeft = newLeft->next;}else{newList = newRight;newRight = newRight->next;}tail=newList ;tail->next = NULL;//以上代码是向newList的第一个节点存入左右两个链表的头节点的较小的元素while (newLeft != NULL|| newRight != NULL)//在&&和||之间踩了大坑,调了一个多小时的bug,让我骂一句真是mmp{if (newLeft == NULL)//左边全部接完了{tail->next = newRight; //右边就直接整条链表接上去newRight = NULL;}else if (newRight == NULL) {//同理,右边接完了tail->next = newLeft;  //左边就直接整条链表接上去,复杂度为O(1),操作爽yynewLeft = NULL;}else if (newLeft->data < newRight->data) {tail->next = newLeft;//上面接一整个链表,这里就是接链表中单个元素的操作newLeft = newLeft->next;  tail = tail->next;tail->next = NULL;}else {tail->next = newRight;newRight = newRight->next;tail = tail->next;tail->next = NULL;}}return newList;   //返回新接好的List,美滋滋。}
再贴上main函数代码

int main() {List list = List(6);list.append(3);list.append(4);list.append(9);list.append(8);list.append(3);list.append(42);list.append(25);list.append(51);list.append(30);Node* test = list.head;for (int i = 0; i < 10; i++){cout << test->data << " ";test = test->next;}Node* newHead = listMergeSort(list.head);cout << endl;Node * temp ;for (int i = 0; i < 10; i++){cout << newHead->data << " ";temp = newHead;if(newHead->next!=NULL) //这里有个坑,踩过,读者试试注释掉这一个判断语句newHead = newHead->next;delete temp;  //注意回收内存}system("pause");}

最后贴上完整代码

# include <iostream>using namespace std;struct Node {int data;Node* next;Node(int val) {data = val;next = NULL;}Node(){data = 0;next = NULL;}};struct List {Node* head;Node* tail;List(int val){head = new Node(val);tail = head;}void append(int val){tail->next = new Node(val);tail = tail->next;}};Node* listMergeSort(Node* head)// n list里面节点的个数{//if (head->next == NULL) //一个元素就返回if (head->next == NULL)return head;Node* fast = head->next;Node* slow = head;while (fast != NULL&&fast->next != NULL){fast = fast->next->next;slow = slow->next;}Node* left = head;Node* right = slow->next;slow->next = NULL;Node* newLeft = listMergeSort(left);Node* newRight = listMergeSort(right);Node * newList ;Node * tail ;if (newLeft->data < newRight->data){newList = newLeft;newLeft = newLeft->next;}else{newList = newRight;newRight = newRight->next;}tail=newList ;tail->next = NULL;while (newLeft != NULL|| newRight != NULL){if (newLeft == NULL){tail->next = newRight;newRight = NULL;}else if (newRight == NULL) {tail->next = newLeft;newLeft = NULL;}else if (newLeft->data < newRight->data){tail->next = newLeft;newLeft = newLeft->next;tail = tail->next;tail->next = NULL;}else {tail->next = newRight;newRight = newRight->next;tail = tail->next;tail->next = NULL;}}Node *temp = newList;return newList;}int main() {List list = List(6);list.append(3);list.append(4);list.append(9);list.append(8);list.append(3);list.append(42);list.append(25);list.append(51);list.append(30);Node* test = list.head;for (int i = 0; i < 10; i++){cout << test->data << " ";test = test->next;}Node* newHead = listMergeSort(list.head); //这里把list的头节点直接进去了2333333,不优雅.。。。cout << endl;Node * temp ;for (int i = 0; i < 10; i++){cout << newHead->data << " ";temp = newHead;if(newHead->next!=NULL) newHead = newHead->next;delete temp;  }system("pause");}

一共137行代码,感觉实现还是蛮优雅的呵呵~(臭不要脸),当然在给那个NewList的头节点加数据的时候代码有点冗余。。。

链表从头节点来分有两种,我的是头节点保存元素的那类链表。


开始时想把 Node* listMergeSort(Node* head) 这个函数的参数带入一个整形参数n (链表元素个数)的,这样好通过n/2求链表中点,后来看到这个博客里面的slow-fast方法。果断用这个方法2333333

参考资料http://www.cnblogs.com/zhanghaiba/p/3534521.html 



原创粉丝点击