链表倒置与合并小结(共四个)
请看目录:
注:代码均在Dev_C++中运行,可能存在谬误,但在此编译器均可通过
在目录中,一、二为一类,三四为一类,其中二为一的加强,四为三的加强
一、链表整体倒置
思路&&步骤:
-
设置前驱指针,遍历指针,前驱指针存上个节点的地址,遍历指针向后走,一直到尾部
-
前驱初始化为NULL,每一次前驱都要覆盖遍历指针所指节点指针域的地址,又因为第一个节点倒置后为尾部,其指针域为空,所以前驱初始化为NULL。遍历指针从真头开始,所以初始化为真头,初始化二者后,前驱指针与遍历指针的关系为:
prev(前驱), cur(遍历) pre->next == cur
且会一直保持这种关系,直到cur到NULL时,pre就到了尾部,也就是倒转后的头部,此时返回新头,及prev所指节点地址
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <ctime>
using namespace std;
const int Len = 10;
typedef struct node
{
int val;
struct node *next;
}ListNode;
ListNode *head = NULL;
ListNode *tail = NULL;
void CreateList();
void PrintList();
void ReverseList();
int main()
{
CreateList();//创建随机数链表
cout << "初始链表打印如下:" << endl;
PrintList();//打印初始链表
ReverseList();//头尾翻转链表
cout << "翻转后链表打印如下:" << endl;
PrintList();//打印翻转后的链表
return 0;
}
void CreateList()
{
srand(time(0));
for (int i = 0; i < Len; ++ i)
{
int rad_num = rand() % 101;
ListNode *new_node = new ListNode();
new_node->val = rad_num;
if (head == NULL) head = tail = new_node;
else
{
tail->next = new_node;
tail = new_node;
tail->next = NULL;
}
}
}
void PrintList()
{
ListNode *phead = head;
while (phead)
{
printf("->%d", phead->val);
phead = phead->next;
}
cout << endl;
return;
}
void ReverseList()
{
ListNode *pre = NULL;
ListNode *cur = head;
while (cur)
{
ListNode *tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
head = pre;
return;
}
运行结果如图:
二、链表局部倒置
思路&&步骤
(1).切割链表,比如1->2->5->4->9->7->8,要求倒置2-5位的数则切割
成1-> 、 2->5->4->9-> 、 7->8
要记住切割相关点,切口处有四个重要的节点,分别为左前驱点、左节点、右节点、右后继点,在上例中,四个节点值分别为1, 2, 9, 7所以,求第p个节点到第q个节点的倒置,四个节点位置需记录
左前驱点位置:节点p前一个节点(p>=1,当p = 1时,左前驱为虚拟头节点)
左节点位置:节点p
右节点位置:节点q
右后继点位置:q->next,当q节点不为尾部时,右后继节点为节点q后一个节点;否则,右后继为NULL;
(2).建立虚拟头节点,针对p = 1的情况,就是在头节点前添加一个新的头节点,将前左驱初始化为该地址,从虚拟头往后走寻找位置,通过遍历,先定到前驱位置,与右节点,然后分别将二者向后移动一次,得到左节点和后继节点地址
(3).斩断联系,使左前驱点与左节点断开,右节点与右后继节点断开
(4).对中间部分即左节点和右节点之间的部分进行倒序,这部分可直接套用整体链表倒置的函数
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <ctime>
using namespace std;
const int Len = 10;
typedef struct node
{
int val;
struct node *next;
}ListNode;
ListNode *head = NULL;
ListNode *tail = NULL;
void CreateList();
void PrintList();
void ReverseList(ListNode *phead);
void ReverseFrom_p_to_q(int p, int q);
int p, q;//翻转第p个节点到第q个节点的部分链表
int main()
{
CreateList();//创建随机数链表
cout << "初始链表打印如下:" << endl;
PrintList();//打印初始链表
cin >> p >> q;//1 <= p,q <= Len
if (p < 1 || p > Len || q < 1 || q > Len) exit(0);
if(p > q) swap(p, q);
ReverseFrom_p_to_q(p, q);
cout << "翻转后链表打印如下:" << endl;
PrintList();//打印翻转后的链表
return 0;
}
void CreateList()
{
srand(time(0));
for (int i = 0; i < Len; ++ i)
{
int rad_num = rand() % 101;
ListNode *new_node = new ListNode();
new_node->val = rad_num;
if (head == NULL) head = tail = new_node;
else
{
tail->next = new_node;
tail = new_node;
tail->next = NULL;
}
}
}
void PrintList()
{
ListNode *phead = head;
while (phead)
{
printf("->%d", phead->val);
phead = phead->next;
}
cout << endl;
return;
}
void ReverseList(ListNode *phead)
{
ListNode *pre = NULL;
ListNode *cur = phead;
while (cur)
{
ListNode *tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
head = pre;
return;
}
void ReverseFrom_p_to_q(int p, int q)
{
ListNode *falsehead = new ListNode();
falsehead->next = head;
ListNode *prev = falsehead;
for (int i = 0; i < p - 1; ++ i)
prev = prev->next;
ListNode *right = prev;
for (int i = 0; i < q - p + 1; ++ i)
right = right->next;
/********************************************/
ListNode *left = prev->next;
ListNode *curr = right->next;
prev->next = NULL;
right->next = NULL;
ReverseList(left);
prev->next = right;
left->next = curr;
head = falsehead->next;
return;
}
运行结果如下:
三、有序链表的合并(包含链表有序化)
思路&&步骤:
(1).建立虚拟头节点,两个链表头指针分别为p, q,通过p,q中数据域数据大小,选择虚拟头节点的链接方向,被链接的,指针后移,未被链接的指针位置不变
(2).最后会剩下两个链表中一个链表的尾部(因为另一个链表已经到尾部了)
把剩下第一个节点地址赋给链接节点的指针域,就能合并完成
(3).链接节点初始为虚拟头节点,会不断向后更新
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <ctime>
using namespace std;
const int Len = 5;
typedef struct node
{
int val;
struct node *next;
}ListNode;
ListNode *CreateList();
ListNode *BubbleSortList(ListNode *phead);
ListNode *MergeTwoList(ListNode *p, ListNode *q);
void PrintList(ListNode *phead);
int main()
{
srand(time(0));
//创建并打印随机数链表 1
ListNode *head1 = CreateList();
cout << "初始链表打印如下:" << endl;
PrintList(head1);
cout << "排序后链表打印如下:" << endl;
head1 = BubbleSortList(head1);
PrintList(head1);
putchar('\n');
//创建并打印随机数链表 2
ListNode *head2 = CreateList();
cout << "初始链表打印如下:" << endl;
PrintList(head2);
cout << "排序后链表打印如下:" << endl;
head2 = BubbleSortList(head2);
PrintList(head2);
putchar('\n');
//PrintList(CreateList());
//合并两个有序链表并使合并后依然有序
//合并并打印
cout << "合并链表1、2并打印可得:" << endl;
PrintList(MergeTwoList(head1, head2));
return 0;
}
ListNode *CreateList()
{
ListNode *head = NULL;
ListNode *tail = NULL;
for (int i = 0; i < Len; ++ i)
{
int rad_num = rand() % 101;
ListNode *new_node = new ListNode();
new_node->val = rad_num;
if (head == NULL) head = tail = new_node;
else
{
tail->next = new_node;
tail = new_node;
tail->next = NULL;
}
}
return head;
}
void PrintList(ListNode *phead)
{
while (phead)
{
printf("->%d", phead->val);
phead = phead->next;
}
cout << endl;
return;
}
ListNode *BubbleSortList(ListNode *head)
{
ListNode * p, * q, * tail = NULL;
ListNode *falsehead = new ListNode();
falsehead->next = head;
head = falsehead;
while (head->next->next != tail)
{
p = head;
q = head->next;
while (q->next != tail)
{
if (q->val > q->next->val)
{
p->next = q->next;
ListNode * temp = q->next->next;
q->next->next = q;
q->next = temp;
q = p->next;
}
p = p->next;
q = q->next;
}
tail = q;
}
return head->next;
}
ListNode *MergeTwoList(ListNode *p, ListNode *q)
{
ListNode *phead = new ListNode();
ListNode *head = phead;
while (p && q)
{
if (p->val < q->val)
{
phead->next = p;
phead = phead->next;
p = p->next;
}
else
{
phead->next = q;
phead = phead->next;
q = q->next;
}
}
if (p) phead->next = p;
if (q) phead->next = q;
return head->next;
}
运行结果如图:
四、稀疏多项式求值
稀疏多项式求值是多项式运算,例如
多项式一:a1x^2 + b1x^4 + c1x^5
多项式二:a2x^2 + b2x^3 + c2x^4
加和可得:(a1+a2)x^2 + b2x^3 + (b1+c2)x^4 + c1x^5
所以,这个多项式求值与合并有序链表只有及其微小的差距,仅仅是当两个节点数据域数据相等时,做一次加和,故有
else if (p->degree == q->degree)
{
p->val = p->val + q->val;
phead->next = p;
phead = phead->next;
p = p->next;
q = q->next;
}
整体代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <ctime>
using namespace std;
typedef struct node
{
int val;
int degree;
struct node *next;
}ListNode;
void CompresNum(int *a, int len);
ListNode *CreateOrderedLsit();
void PrintList(ListNode *phead);
ListNode *MergeTwoList(ListNode *p, ListNode *q);
int main()
{
srand(time(0));
ListNode *head1 = CreateOrderedLsit();
cout << "初始链表1打印如下:" << endl;
PrintList(head1);
ListNode *head2 = CreateOrderedLsit();
cout << "初始链表2打印如下:" << endl;
PrintList(head2);
ListNode *head = MergeTwoList(head1, head2);
cout << "合并链表1、2并打印可得:" << endl;
PrintList(head);
return 0;
}
void CompresNum(int *a, int len)
{
int i = 0;
for (i = 0; i < len - 1; ++ i)
if (a[i] == a[i+1]) a[i] += 10*(i+1);
sort(a, a + len);
return;
}
ListNode *CreateOrderedLsit()
{
ListNode *head = NULL;
ListNode *tail = NULL;
int len = rand() % 5 + 1;
int *a = new int[len];
for (int i = 0; i < len; ++ i)
a[i] = rand() % 10;
sort(a, a + len);
CompresNum(a, len);
for (int i = 0; i < len; ++ i)
{
int num = rand() % 20 + 1;
ListNode *new_node = new ListNode();
new_node->degree = a[i];
new_node->val = num;
if (head == NULL) head = tail = new_node;
else
{
tail->next = new_node;
tail = new_node;
tail->next = NULL;
}
}
return head;
}
void PrintList(ListNode *phead)
{
while (phead)
{
printf("->%dx^%d ", phead->val, phead->degree);
phead = phead->next;
}
cout << endl;
return;
}
ListNode *MergeTwoList(ListNode *p, ListNode *q)
{
ListNode *phead = new ListNode();
ListNode *head = phead;
while (p && q)
{
if (p->degree < q->degree)
{
phead->next = p;
phead = phead->next;
p = p->next;
}
else if (p->degree == q->degree)
{
p->val = p->val + q->val;
//printf("%d\n", p->val)
phead->next = p;
phead = phead->next;
p = p->next;
q = q->next;
}
else
{
phead->next = q;
phead = phead->next;
q = q->next;
}
}
if (p) phead->next = p;
if (q) phead->next = q;
return head->next;
}
运行结果如下:
分享结束~感谢观看!