链表倒置与合并小结(含稀疏多项式求值)

链表倒置与合并小结(共四个)


请看目录:


注:代码均在Dev_C++中运行,可能存在谬误,但在此编译器均可通过

在目录中,一、二为一类,三四为一类,其中二为一的加强,四为三的加强

一、链表整体倒置

思路&&步骤:

  1. 设置前驱指针,遍历指针,前驱指针存上个节点的地址,遍历指针向后走,一直到尾部

  2. 前驱初始化为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;
} 

运行结果如下:

运行结果
运行结果
运行结果

分享结束~感谢观看!

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值