参考资料:《数据结构与算法分析》(第三版英文版)
书本题目: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),操作爽yy
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;
}
}
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