把两个从大到小的有序链表合并成一个链表,新的链表是一个从小到大的有序链表
2016-07-16 22:59
435 查看
实现一个函数,把两个从大到小的有序链表合并成一个链表,新的链表是一个从小到大的有序链表。
可以分成两个思路:
1.先把两个链表合并成一个链表,合并后的链表从大到小排序
2.将链表逆置,得到从小到达排序的链表
由于两个链表是有序的,因此我们可以分别从两个链表的第一个节点开始比较,把用于指向新链表的指针指向头节点值比较大的链表,记这个链表为list1。然后指向list1的第二个节点,而lsit2则不动,仍然指向头节点,list1的第二个节点继续比较,取较大者为新的节点。
如果两个链表不等长,那么必有一个链表先遍历完,只需要把还没有遍历完的链表剩下的部分加入到新的链表即可。
用这种方式,就可以在O(len1+len2)完成任务,且不需要再构造新的存储空间。
其实只要用两个指针指向相邻的两个节点,然后把指向逆转(next指针),当然在此之前要保存好后一个节点原来的next指针(第三个节点),否则就失去这个链表的踪迹了。
至此,就完成了链表合并以及逆置,完整代码如下:
对两个序列:
100, 77, 52, 23, 10, 4, 0
83, 80, 26, 15, 3, 2, 1, 0
操作后的结果:
可以分成两个思路:
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
操作后的结果:
相关文章推荐
- Android Netd ndc (Native Daemon Connector)
- Java(通过反射获取方法并使用)
- MySQL开启慢查询
- 开发常用框架
- 元素节点、属性节点、文本节点 的节点属性
- 洛谷 P2661 信息传递
- Python if..else
- CNN初步-2
- NumbrtPicker扩展方法
- c++类实例化的两种方式
- 排序算法之 —— 快速排序(五)
- json
- 腾讯2017实习生编程之算法基础-字符移位
- cgi表单的处理
- 继承的简单理解,原型对象继承,类继承,混合方式继承
- 《JavaScript高级程序设计》——原型对象、原型链
- Mybatis深入了解(五)----动态SQL
- 爬取微信公众号
- 【Thinking in Java真题精选】1. 类的初始化顺序
- 实例:创建、启动、停止和绑定一个Service