有两个不带头结点的单链表,且数据元素为整数型,且递增有序。 (此时假设它输入的时候就已经是递增有序的单链表了)
算法实现目标:将这两个单链表合并为一个递减有序的单链表
思路:可以利用这两个链表本来就是递增有序的特性进行合并,然后再进行逆序,即可得到递减有序链表。
链表类:
//链表类
class List {
public:
int val;
List* next;
public:
List() : val(0), next(nullptr) {}
List(int x) : val(x), next(nullptr) {}
List(int x, List* next) : val(x), next(next) {}
};
合并链表函数
使用了3个指针:now,p1,p2
1.先比较两个链表头结点的数值的大小,选择更小者作为新链表的头结点。
2.此后设置now指向新链表的当前结点,而p1指向链表1未加入新链表的结点,p2指向链表2未加入新链表的结点。
3.p1和p2进行数值比较,选择结点值更小的加入新链表,而p1/p2要指向p1->next/p2->next(即往前移)
4.以此类推,最后有3种情况,即链表1和链表2都全并入新链表或 链表1加入新链表 或 链表2加入新链表。只需要判断p1和p2哪个为空,在now后面接上剩余链表即可(因为已经有序了)
个人觉得该思路的好处是一次遍历即可合并,并且不用额外空间
//该函数作用:合并递增链表为一个新的递增链表
int MergeList1(List* l1, List* l2) {
//先判断l1、l2是否为空节点
if (l1 == nullptr && l2 == nullptr)
return 0;
if (l1 == nullptr) return 2;
if (l2 == nullptr) return 1;
List *head,*now;
int flag;
//选取首结点更小的链表作为头结点,最后返回的也是该链表
if (l1->val < l2->val) {
flag = 1;//选择链表1
head = now = l1;
l1 = l1->next;
}
else {
flag = 2;//选择链表2
head= now = l2;
l2 = l2->next;
}
//两个都不为nullptr才能继续
while (l1!=nullptr && l2!=nullptr) {
if (l1->val < l2->val) { //如果l1的结点更小 那么下一个结点应该是l1
now->next = l1;
l1 = l1->next;
now = now->next;
}
else {
now->next = l2;
l2 = l2->next;
now = now->next;
}
}
//此时有3种情况: l1是空 或 l2是空 或 l1和l2都是空
//如果选择链表1作为头结点 最后要返回的是链表1 因此在now的后面接上链表2
if (flag == 1) {
now->next = l2;
l1 = head;
}
//如果选择链表2作为头结点 最后要返回的是链表2 因此在now的后面接上链表1
else {
now->next = l1;
l2 = head;
}
return flag;
}
逆序函数
三指针法
//该函数作用:将链表逆序(并且返回新的头结点)
List* Reverse(List* l) {
List* p1, *p2, *p3;//逆序方法:三指针法
List* head;
head = l;
p1 = l;
p2 = p1->next;
p3 = p2->next;
while (p3!=nullptr) {
p2->next = p1;
p1 = p2;
p2 = p3;
p3 = p2->next;
}
p2->next = p1;
head->next = nullptr;
return p2; //此时p2是新的头结点(即原链表的尾结点) 因此返回p2
}
Show(展示函数)
//该函数作用:展示链表
void Show(List* l) {
//cout << "head->";
while (l != nullptr) {
cout << l->val << "->";
l = l->next;
}
cout << "nullptr" << endl;
}
测试程序
//主测试程序
int main() {
cout << "本程序为【将两个不带头结点的递增有序单链表(数据元素为整数)合并为递减有序单链表】的算法测试程序" << endl;
cout << endl;
int n1, n2;
List* p1=nullptr, * p2=nullptr;
List* head1=nullptr, *head2=nullptr;
//输入链表
cout << "请输入 链表1 的结点个数:" ;
cin >> n1;
for (int i = 1; i <= n1; i++) {
cout << "请输入 链表1 的第 " << i << " 个结点的值:";
int temp1;//值
cin >> temp1;
if (i == 1) {
p1 = new List(temp1);
head1 = p1;
continue;
}
p1->next = new List(temp1);
p1 = p1->next;
}
cout << "请输入 链表2 的结点个数:";
cin >> n2;
for (int i = 1; i <= n2; i++) {
cout << "请输入 链表2 的第 " << i << " 个结点的值:";
int temp2;//值
cin >> temp2;
if (i == 1) {
p2 = new List(temp2);
head2 = p2;
continue;
}
p2->next = new List(temp2);
p2 = p2->next;
}
cout << endl;
int Lflag;
cout << "链表1:";
Show(head1);
cout << "链表2:";
Show(head2);
Lflag = MergeList1(head1, head2);
//到这里应该已经成功升序合并了
if (Lflag == 1) {
cout << endl;
cout << "合并链表1和链表2:";
Show(head1);
List* temphead = Reverse(head1);
cout << "合并链表1和链表2并将其逆序:";
Show(temphead);
}
else if (Lflag == 2) {
cout << endl;
cout << "合并链表1和链表2:";
Show(head2);
List* temphead = Reverse(head2);
cout << "合并链表1和链表2并将其逆序:";
Show(temphead);
}
else if (Lflag == 0)
cout << "链表为空";
cout << endl;
return 0;
}
测试结果