
- 你需要先会写数组的归并排序。
- 除此之外,你还要对递归的过程有很清晰的认识。
- 你需要会用熟练的使用指针,这是C++玩家必备技能。
- 代码里的List,可能命名成Node更加合适,我也不知道我当时这么想的,命了个这鼠名字,看着挺别扭的。
掌握归并排序的核心思想就行了,将大区间分解成两个小区间之后呢,双指针,把小的数值一个一个的压入新的容器(这里自然是指链表了)里面,等待两个子区间其中有一个全部压入了之后,把另外一个区间剩余的全部压入,返回。这就完成归并的基本逻辑阐述了。
归并排序对新手是很具有挑战性的,因为要用到递归还有双指针,比较难的是前者,太抽象了,所以,新手不妨用一个长度为3,为5,为7的数组先多模拟一下,想清楚该怎么做了再去做。
下面附上python代码,C玩家可以当成伪代码读,因为篇幅比较简单,精髓可能更容易get到吧!
def f(num):
if len(num)<=1:
return num
l,r=f(num[:len(num)//2]),f(num[len(num)//2:])
ans=[]
a,b=0,0
while a
仿照上面的逻辑,我们开始准备链表归并。
首先,我们先把链表建立好,这个没啥,
其次,把链表的补丁打好,打补丁主要还是为了仿照数组归并的思路,不然指针太能绕了头都给指晕。
主要的补丁其实就一个,就是上面python代码里面第四行,递归分解的那一部分,我在类里面写了个split方法,该方法能够在给定位置切上一刀,使原来的链表切断,并且返回将后半部分构成新的链表返回。
List *getKthNode(int position) {//返回position位置的指针,方便我分割链表。
List *p = head.next;
while (position--) {
p = p->next;
}
return p;
}
mylist split(int from) {//这个函数我用来分割原来的链表,list[:from],list[from:]
//同时把原来的链表卡断,返回后半部分
List *ends = NULL;
int count = 0;
List *p = &head;
for (int i = from; i > 0; --i) {
p = p->next;
}//定位分割点之前的那个点位
mylist ret;
List newHead = List{0, getKthNode(from)};
ret = mylist(newHead);
p->next = NULL;
length = from;
return ret;
}
这里还需要借助getKthNode方法的帮助,算是个小补丁吧,帮忙找到第position个结点(本链表有头结点,头结点是哨兵节点,帮助写代码用的,没实际作用,还有一种是没有头结点的链表写法,每一个节点都是真实且有意义的,不做赘述)。
完成了split方法,再然后就可以直接写归并了,(代码太乱了,命名也不规范,见谅):
mylist mylistMergeSort(mylist x) {
if (x.length == 1) {
return x;
}
mylist r = x.split(x.length / 2);
mylist l = x;
mylist rpart = mylistMergeSort(r);
mylist lpart = mylistMergeSort(l);
List *p1 = rpart.head.next;
List *p2 = lpart.head.next;
List *p3 = new List;
List *p4 = p3;
while (p1 and p2) {
if (p1->val <= p2->val) {
p3->next = p1;
p1 = p1->next;
} else {
p3->next = p2;
p2 = p2->next;
}
p3 = p3->next;
}
while (p1) {
p3->next = p1;
p1 = p1->next;
p3 = p3->next;
}
while (p2) {
p3->next = p2;
p2 = p2->next;
p3 = p3->next;
}
List ans = {0, p4->next};
return mylist(ans);
}
为了方便和python数组归并对照,加深理解,我再发一遍python:
def f(num):
if len(num)<=1:
return num
l,r=f(num[:len(num)//2]),f(num[len(num)//2:])
ans=[]
a,b=0,0
while a
大致就这么多,细细品吧,码友,下一个帖子,祝你好运。
全部代码: 头文件://
// Created by chen on 2022/4/20.
//
#ifndef STANDARDLIST_MYLIST_H
#define STANDARDLIST_MYLIST_H
#endif //STANDARDLIST_MYLIST_H
#include
#include
using namespace std;
struct List {
int val;
List *next;
};
class mylist {
public:
List head;
int length;
mylist(mylist const &t) {//引用
head = t.head;
length = t.length;
}
mylist(List givedHead) {//根据头结点构造链表,为了写归并,做个铺垫(其实不写也可以,灵活点总归是好的)
head = givedHead;
List *p = &head;
length = 0;
while (p->next != NULL) {
length++;
p = p->next;
}
}
mylist() {
List pnode;
head = pnode;
head.next = NULL;
length = 0;
}
void insert(int val, int position = -1) {
if (position == -1) {
position = length;//不写append方法了,如果不填写position就默认是append。
}
List *p = &head;
while (position--) {
p = p->next;//找到目标位置的前一个点,head节点作为哨兵}
}
List *mem = p->next;//head->0->1->2 要在0号位置插入元素,需要记住0这个位置当前的节点
/*错的List newData = {val, mem};
p->next = &newData;*/
List *t = new List{val, mem};
p->next = t;
length++;
}
void deleteNode(int position) {
List *p = &head;
while (position--) {
p = p->next;
}
List *mem = p->next;
p->next = p->next->next;
free(mem);
length--;
}
List *getKthNode(int position) {//返回position位置的指针,方便我分割链表。
List *p = head.next;
while (position--) {
p = p->next;
}
return p;
}
mylist split(int from) {//这个函数我用来分割原来的链表,list[:from],list[from:]
//同时把原来的链表卡断,返回后半部分
List *ends = NULL;
int count = 0;
List *p = &head;
for (int i = from; i > 0; --i) {
p = p->next;
}//定位分割点之前的那个点位
mylist ret;
List newHead = List{0, getKthNode(from)};
ret = mylist(newHead);
p->next = NULL;
length = from;
return ret;
}
void print() {
List *p = head.next;
while (p) {
cout << p->val << " ";
p = p->next;
}
cout << endl;
}
};
mylist mylistMergeSort(mylist x) {
if (x.length == 1) {
return x;
}
mylist r = x.split(x.length / 2);
mylist l = x;
mylist rpart = mylistMergeSort(r);
mylist lpart = mylistMergeSort(l);
List *p1 = rpart.head.next;
List *p2 = lpart.head.next;
List *p3 = new List;
List *p4 = p3;
while (p1 and p2) {
if (p1->val <= p2->val) {
p3->next = p1;
p1 = p1->next;
} else {
p3->next = p2;
p2 = p2->next;
}
p3 = p3->next;
}
while (p1) {
p3->next = p1;
p1 = p1->next;
p3 = p3->next;
}
while (p2) {
p3->next = p2;
p2 = p2->next;
p3 = p3->next;
}
List ans = {0, p4->next};
return mylist(ans);
}
源文件:
#include
#include "mylist.h"
using namespace std;
int main() {
mylist ml = mylist();
for (int i = 0; i < 10; i++) {
if (ml.length) {
int x = rand() % (ml.length + 1);
ml.insert(i, x);
cout << i << " 插入位置是" << x << " ";
} else {
ml.insert(i);
cout << i << " 插入位置是" << 0 << " ";
}
ml.print();
}
cout << "排序前:";
ml.print();
cout << "排序后:";
mylistMergeSort(ml).print();
//注意,本排序之后ml值会发生变化,还要再定义一个链表存储下,有点不足。
//example:
//0 插入位置是0 0
//1 插入位置是1 0 1
//2 插入位置是1 0 2 1
//3 插入位置是1 0 3 2 1
//4 插入位置是3 0 3 2 4 1
//5 插入位置是4 0 3 2 4 5 1
//6 插入位置是6 0 3 2 4 5 1 6
//7 插入位置是0 7 0 3 2 4 5 1 6
//8 插入位置是8 7 0 3 2 4 5 1 6 8
//9 插入位置是3 7 0 3 9 2 4 5 1 6 8
//排序前:7 0 3 9 2 4 5 1 6 8
//排序后:0 1 2 3 4 5 6 7 8 9
return 0;
}
本人能力有限,代码中或许会存在部分bug,没有测出来,所以到时候发现了还请多多关照本新手
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)