前言
记录用C++实现基于单链表的归并排序
代码
一共三个文件SingleLinkedList.h, CNode.h以及main.cpp。
首先是CNode.h
#ifndef _NODE_H__
#define _NODE_H__
class CNode{
private:
int data;
CNode *nextNode;
public:
CNode();
void setData(int iData);
int getData() const;
void setNextNode(CNode *nextNode);
CNode* getNextNode() const;
};
#endif
接下来是SingleLinkedList.h,复用的之前写过的代码,添加了一些方法。
#ifndef _SINGLE_LINKEDLIST_H__
#define _SINGLE_LINKEDLIST_H__
#include "CNode.h"
//#include "SingleLinkedList.cpp"
class SingleLinkedList{
private:
CNode *firstNode;
public:
SingleLinkedList();
~SingleLinkedList();
void insertAtTheFront(int data);
void insertAtTheMiddle(int data, int position);
void insertAtTheEnd(int data);
void deleteFromTheFront();
void deleteFromTheMiddle(int position);
void deleteFromTheEnd();
bool search(int data);
void display();
CNode* merge(CNode *p,CNode *q);
CNode* mergeSort(CNode *head);
CNode* getMid(CNode *head);
CNode* mergesort();
};
#endif
最后是main.cpp, 针对单链表的实现主要复用了之前C++实现单链表的代码,不过发现并修改了不少问题,找时间回头会把那篇博客也改一下。
#include <iostream>
#include "CNode.h"
#include "SingleLinkedList.h"
using namespace std;
CNode::CNode(){
this->nextNode = NULL;
};
void CNode::setData(int iData){
this->data = iData;
};
int CNode::getData() const{
return data;
}
void CNode::setNextNode(CNode *nextNode){
this->nextNode = nextNode;
};
CNode* CNode::getNextNode() const{
return nextNode;
};
SingleLinkedList::SingleLinkedList(){
firstNode = NULL;
cout << "SUCCESSFULLY BUILD" << endl;
};
SingleLinkedList::~SingleLinkedList(){
};
void SingleLinkedList::insertAtTheFront(int data){
CNode *p = new CNode;
p->setData(data);
if (firstNode == NULL) {
firstNode = new CNode;
this->firstNode->setData(data);
}
else {
p->setNextNode(firstNode);
this->firstNode = p;
}
};
void SingleLinkedList::insertAtTheMiddle(int data, int position){
//add node s at the position
CNode *p = firstNode;
CNode *s = new CNode;
s->setData(data);
if (firstNode == NULL) {
firstNode = new CNode;
this->firstNode->setData(data);
return;
}
if (position == 1){
insertAtTheFront(data);
return;
}
for (int i = 0; i < position - 2; i++){
if (p->getNextNode() != NULL) p = p->getNextNode();
else {
cout << "ERROR";
return;
}
}
s->setNextNode(p->getNextNode());
p->setNextNode(s);
};
void SingleLinkedList::insertAtTheEnd(int data){
CNode *p = firstNode;
CNode *s = new CNode;
s->setData(data);
while (p->getNextNode() != NULL){
p = p->getNextNode();
}
p->setNextNode(s);
};
void SingleLinkedList::deleteFromTheFront(){
if (firstNode == NULL) return;
else if (firstNode->getNextNode() == NULL){
firstNode = NULL;
return;
}
CNode *p = firstNode->getNextNode();
firstNode = p;
};
void SingleLinkedList::deleteFromTheMiddle(int position){
CNode *p = firstNode;
CNode *s = new CNode;
if (firstNode == NULL) return;
if (position == 1){
deleteFromTheFront();
return;
}
for (int i = 0; i < position - 2; i++){
if (p->getNextNode() != NULL) p = p->getNextNode();
else {
cout << "ERROR";
return;
}
}
p->setNextNode(p->getNextNode()->getNextNode());
};
void SingleLinkedList::deleteFromTheEnd(){
CNode *p = firstNode;
if (p == NULL){
cout << "ERROR" << endl;
return;
}
if (p->getNextNode() == NULL){
firstNode = NULL;
return;
}
while (p->getNextNode()->getNextNode() != NULL) p = p->getNextNode();
p->setNextNode(NULL);
};
bool SingleLinkedList::search(int data){
CNode *p = firstNode;
while (p->getNextNode() != NULL){
if (p->getData() == data) return true;
p = p->getNextNode();
}
if (p->getData() == data) return true;
else return false;
};
void SingleLinkedList::display(){
//display the single linked list
CNode *p = firstNode;
int i = 0;
while (p->getNextNode() != NULL){
cout << ++i << ":" << p->getData() << endl;
p = p->getNextNode();
}
cout << ++i << ":" << p->getData() << endl;
};
CNode* SingleLinkedList::getMid(CNode* head){
//find the middle node
if (!head) return NULL;
if (!head->getNextNode()) return head;
CNode *slow = head;
CNode *fast = head->getNextNode();
while (fast && fast->getNextNode())
{
slow = slow->getNextNode();
fast = fast->getNextNode()->getNextNode();
}
return slow;
}
CNode* SingleLinkedList::merge(CNode *a, CNode *b) {
//merge two sorted arrays
if (a == NULL) return b;
if (b == NULL) return a;
CNode *ret = NULL;
CNode *tail = NULL;
ret = new CNode;
tail = ret;
while (a && b)
if (a->getData() < b->getData())
{
tail->setNextNode(a);
tail = tail->getNextNode();
a = a->getNextNode();
}
else
{
tail->setNextNode(b);
tail = tail->getNextNode();
b = b->getNextNode();
}
if (a)
tail->setNextNode(a);
if (b)
tail->setNextNode(b);
CNode *del = ret;
ret = ret->getNextNode();
delete del;
return ret;
}
CNode* SingleLinkedList::mergeSort(CNode *head) {
//mergesort from the node head
if (!head) return NULL;
if (!head->getNextNode()) return head;
CNode *mid = getMid(head);
CNode *nextPart = NULL;
if (mid)
{
nextPart = mid->getNextNode();
mid->setNextNode(NULL);
}
return merge(
mergeSort(head),
mergeSort(nextPart)
);
}
CNode* SingleLinkedList::mergesort(){
//merge sort the whole single linked list
return firstNode=mergeSort(firstNode);
}
int main(){
SingleLinkedList theList;
theList.insertAtTheFront(44);
theList.insertAtTheFront(88);
theList.insertAtTheFront(66);
theList.insertAtTheFront(22);
theList.insertAtTheFront(55);
theList.insertAtTheFront(11);
theList.insertAtTheFront(33);
theList.insertAtTheFront(99);
theList.display();
theList.mergesort();
theList.display();
}
注意点
只要理解了递归的思想,归并排序总的来说还是比较好理解的,上核心代码:
CNode* SingleLinkedList::mergeSort(CNode *head) {
//mergesort from the node head
if (!head) return NULL;
if (!head->getNextNode()) return head;
CNode *mid = getMid(head);
CNode *nextPart = NULL;
if (mid)
{
nextPart = mid->getNextNode();
mid->setNextNode(NULL);
}
return merge(
mergeSort(head),
mergeSort(nextPart)
);
}
比数组的归并要难实现一点点,但原理没变。找到中间结点,分别对左边和右边的链表进行归并排序,最后将左右两个链表归并起来。注意递归头,在head无后继结点时生效。
自此,我们的目标就比较明确了。
1.从结点Node开始的归并排序 即上面的mergeSort()
2.找到中间结点,即getMid()
3.归并两个有序单链表,即merge()
特地把找中间节点拿出来说,因为这段找中间节点的代码是从网上找来的,我觉得很有新意也很聪明:
CNode* SingleLinkedList::getMid(CNode* head){
//find the middle node
if (!head) return NULL;
if (!head->getNextNode()) return head;
CNode *slow = head;
CNode *fast = head->getNextNode();
while (fast && fast->getNextNode())
{
slow = slow->getNextNode();
fast = fast->getNextNode()->getNextNode();
}
return slow;
}
最后就是归并的merge写法了,将两个链表从左向右遍历,每次都取最小的一个拿出来,直至遍历完成。