您的位置:首页 > 其它

把两个从大到小的有序链表合并成一个链表,新的链表是一个从小到大的有序链表

2016-07-16 22:59 435 查看
实现一个函数,把两个从大到小的有序链表合并成一个链表,新的链表是一个从小到大的有序链表。

可以分成两个思路:

1.先把两个链表合并成一个链表,合并后的链表从大到小排序

2.将链表逆置,得到从小到达排序的链表

链表合并

最粗暴的方法,遍历第一个链表的节点,和第二个链表的每一个节点比较,找出最小者作为链表的新节点插入,这个方法的时间复杂度为O(len1*len2)。

由于两个链表是有序的,因此我们可以分别从两个链表的第一个节点开始比较,把用于指向新链表的指针指向头节点值比较大的链表,记这个链表为list1。然后指向list1的第二个节点,而lsit2则不动,仍然指向头节点,list1的第二个节点继续比较,取较大者为新的节点。

如果两个链表不等长,那么必有一个链表先遍历完,只需要把还没有遍历完的链表剩下的部分加入到新的链表即可。

用这种方式,就可以在O(len1+len2)完成任务,且不需要再构造新的存储空间。

List_t *pNew = NULL;
List_t *pCur = NULL;

if(h1 == NULL || h2 == NULL){//如果其中一个链表为空,则不需要比较,返回
return NULL;
}

//找出头结点较大的链表,把新链表的指针指向它
if(h1->data >= h2->data){
pNew = h1;
h1 = h1->next;
}
else{
pNew = h2;
h2 = h2->next;
}
pCur = pNew;

do{
//取节点较大值作为新链表的节点
if(h1->data >= h2->data){
pCur->next = h1;
pCur = pCur->next;
h1 = h1->next;
}
else{
pCur->next = h2;
pCur = pCur->next;
h2 = h2->next;
}

}while(h1 != NULL && h2 != NULL);//用do-while,因为第一次h1和h2肯定不为空,否则前面已经返回

List_t *cnt;
if(h1 == NULL && h2 == NULL){//两个链表一样长,新的链表已经组合完成,返回
return pNew;
}
pCur->next = h1?h1:h2;//必有一个为空,直接把不为空的剩余部分链到新链表后面


链表逆置

得到新的链表后,要把链表进行逆置,一开始可能会想到构造一个新的链表,将原链表遍历一遍,然后将节点一个个复制下来。

其实只要用两个指针指向相邻的两个节点,然后把指向逆转(next指针),当然在此之前要保存好后一个节点原来的next指针(第三个节点),否则就失去这个链表的踪迹了。

List_t *p2 = pNew->next;
pNew->next = NULL;//原头节点变为尾节点,指向NULL
List_t *tmp;

while(p2 != NULL){
tmp = p2->next; //保存第三个节点的地址
p2->next = pNew;//逆转指向
pNew = p2;//指针后移,原先指向第一个节点,现在指向第二个节点
p2 = tmp;//指针后移,原先指向第二个节点,现在指向第三个节点
}


至此,就完成了链表合并以及逆置,完整代码如下:

#include <string.h>
#include <malloc.h>
#include <iostream>
#include <vector>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>

using namespace std;

typedef struct mList{
int data;
struct mList *next;
}List_t;

void PrintData(List_t* L){
List_t* tmp = L;
while(tmp != NULL){
cout << tmp->data << " ";
tmp = tmp->next;
}
cout << endl;
}

List_t* mergeList(List_t* h1, List_t* h2){
List_t *pNew = NULL; List_t *pCur = NULL; if(h1 == NULL || h2 == NULL){//如果其中一个链表为空,则不需要比较,返回 return NULL; } //找出头结点较大的链表,把新链表的指针指向它 if(h1->data >= h2->data){ pNew = h1; h1 = h1->next; } else{ pNew = h2; h2 = h2->next; } pCur = pNew; do{ //取节点较大值作为新链表的节点 if(h1->data >= h2->data){ pCur->next = h1; pCur = pCur->next; h1 = h1->next; } else{ pCur->next = h2; pCur = pCur->next; h2 = h2->next; } }while(h1 != NULL && h2 != NULL);//用do-while,因为第一次h1和h2肯定不为空,否则前面已经返回 List_t *cnt; if(h1 == NULL && h2 == NULL){//两个链表一样长,新的链表已经组合完成,返回 return pNew; } pCur->next = h1?h1:h2;//必有一个为空,直接把不为空的剩余部分链到新链表后面

PrintData(pNew);

List_t *p2 = pNew->next; pNew->next = NULL;//原头节点变为尾节点,指向NULL List_t *tmp; while(p2 != NULL){ tmp = p2->next; //保存第三个节点的地址 p2->next = pNew;//逆转指向 pNew = p2;//指针后移,原先指向第一个节点,现在指向第二个节点 p2 = tmp;//指针后移,原先指向第二个节点,现在指向第三个节点 }

PrintData(pNew);

return pNew;
}

int main(){
int data1[] = {100, 77, 52, 23, 10, 4, 0};
int data2[] = {83, 80, 26, 15, 3, 2, 1, 0};

int l1 = sizeof(data1)/sizeof(data1[0]);
List_t *q = NULL;
List_t *h1 = NULL;
for(int idx = 0; idx < l1; idx++){
List_t *p = (List_t*)malloc(sizeof(List_t));
p->data = data1[idx];
p->next = NULL;

if(h1 == NULL){
h1 = p;
}
else{
q->next = p;
}
q = p;
}

int l2 = sizeof(data2)/sizeof(data2[0]);
q = NULL;
List_t *h2 = NULL;
for(int idx = 0; idx < l2; idx++){
List_t *p = (List_t*)malloc(sizeof(List_t));
p->data = data2[idx];
p->next = NULL;

if(h2 == NULL){
h2 = p;
}
else{
q->next = p;
}
q = p;
}

mergeList(h1,h2);
}


对两个序列:

100, 77, 52, 23, 10, 4, 0

83, 80, 26, 15, 3, 2, 1, 0

操作后的结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: