链表相关其他算法题2|排序插入节点|按数据类型拆分链表|输出次数最多的前k个词|三个链表公共元素|两个整数数位求和(C)

排序插入节点

设民航公司有一个自动预订飞机票的系统,该系统中有一张用双重链表示的乘客表,表中节点按乘客姓氏的字母序相连
为该系统写一个当任意乘客订票时修改乘客表的算法

算法思想

av是可用数组空间的最小下标

typedef struct Node
{
	char data[maxsize];
	int prev, next;
}unode;

void Insert(unode user[max], int av)
{
	// 读入字符串s,是乘客的姓名
	scanf("%s", s);
	// 将字符串s的内容拷贝到新的节点的数据域
	strcopy(user[av].data, s);
	// 创建工作指针cur
	cur = 1;
	
	if (strcmp(user[cur].data, s) < 0)
	{
		// 沿右链查找
		while (cur && strcmp(user[cur].data, s) < 0)
		{
			unode prev = cur;
			cur = user[cur].next;
		}
		user[av].next = cur;
		user[av].prev = prev;
		// 将新节点链入表中
		user[prev].next = av;
		user[cur].prev = av;
	}
	else
	{
		while (cur && strcmp(user[cur].data ,s) > 0)
		{
			unode prev = cur;
			cur = user[cur].next;
		}
		user[av].next = prev;
		user[av].prev = cur;
		// 将新节点链入表中
		user[prev].prev = av;
		user[prev].next = av;
	}
}

按数据类型拆分链表

已知L为没有头节点的单链表中第一个节点的指针,每个节点数据域存放一个字符,该字符可能是英文字母字符或数字字符或其他字符
构造三个以带头节点的单循环链表表示的线性表,是每个表中只含有同一类字符

算法思想

首先要构造含有这三类字符的表头节点
然后从原链表的第一个节点开始,根据数据域的类型分别插入到三个链表之一
采用前插法

void OneToThree(LinkList &L, &l1, &l2, &l3)
{
	l1 = (LinkList)malloc(sizeof(LNode));
	l2 = (LinkList)malloc(sizeof(LNode));
	l3 = (LinkList)malloc(sizeof(LNode));
	l1->next = l1, l2->next = l2, l3->next = l3;

	LNode* cur = L, *next;
	while (cur)
	{
		next = cur->next;
		if (cur->data >= 'a' && cur->data <= 'z' || cur->data >= 'A' && cur->data <= 'Z')
		{
			cur->next = l1->next;
			l1->next = cur;
		}
		else if (cur->data >= '0' && cur->data <= '9')
		{
			cur->next = l2->next;
			l2->next = cur;
		}
		else
		{
			cur->next = l3->next;
			l3->next = cur;
		}
		cur = next;
	}
}

输出次数最多的前k个词

设键盘输入n个英语单词,输入格式为n,w1,w2,…wn,其中n表示随后输入英语单词的个数
建立一个单向链表,实现

  1. 如果单词重复出现,只在链表中保留一个
  2. 有一个计数域,记录该单词重复的次数,然后输出出现次数最多的前k个单词
算法思想

用字符数组表示英文单词,判断单词是否相等,使用strcmp函数

typedef struct Node
{
	// 频度域
	int freq;
	char word[maxsize];
	struct Node* next;
}LNode, *LinkList;

LinkList Create()
{
	LinkList L;
	// 申请头节点
	L = (LinkList)malloc(sizeof(LNode));
	// 链表初始化
	L->next = NULL;

	// 建立n个节点的链表
	for (i = 1; i <= n; i++)
	{
		scamf("%s", s);
		// cur是工作指针,prev是前驱指针
		LNode* cur = L->next;
		LNode* prev;
		while (cur)
		{
			if (strcmp(cur->data, s) == 0)
			{
				cur->freq++;
				break;
			}
			else
			{
				// 指针后移
				prev = cur;
				cur = cur->next;
			}
		}
		// 该词没出现过,插入链表
		if (cur == NULL)
		{
			cur = (LinkList)malloc(sizeof(LNode));
			strcopy(cur->data, s);
			cur->freq = 1;
			cur->next = NULL;
			prev->next = cur;
		}
	}
	return L;
}

void CreatOut()
{
	LinkList L;
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL;

	for (i = 1; i <= n; i++)
	{
		scanf("%s", s);
		LNode* cur = L->next;
		LNode* prev = cur;
		while (cur)
		{
			if (strcmp(cur->data, s) == 0)
			{
				// 重复出现,频度+1
				cur->freq++;
				prev->next = cur->next;
				prev = L;
				LNode* cur2 = L->next;
				while (cur2->freq > cur->freq)
				{
					prev = cur2;
					cur2 = cur2->next;
				}
				prev->next = cur;
				cur->next = cur2;
			}
			else
			{
				prev = cur;
				cur = cur->next;
			}
		}
		if (cur == NULL)
		{
			cur = (LinkList)malloc(sizeof(LNode));
			strcopy(cur->data, s);
			cur->freq = 1;
			cur->next = NULL;
			prev->next = cur;
		}
	}
	int k, i = 0;
	scanf("输入要输出单词的个数%d", &k);
	cur = L->next;
	// 输出频度最高的k个单词
	while (cur && i < k)
	{
		printf("第%3d个单词%s出现%3d次\n", ++i, cur->data, cur->freq);
		cur = cur->next;
	}
}

三个链表公共元素

已知三个带头节点的线性链表A、B和C,节点均从小到大非递减次序排列
对A表,使A链表仅留下三个表中均包含的数据元素的节点,且没有值相同的节点,并释放所有无用的节点
m,n,p表示链表长度

算法思想

首先查找A和B的公共数据,再去C中找有无该数据,要消除重复元素,要保存前驱

LinkList Common(LinkList &A, &B, &C)
{
	LNode* cur1 = A->next, *cur2 = B->next, *cur3 = C->next;
	// prev是A表中当前节点的前驱指针
	LNode* prev = A;
	// ABC均不为空时,查找共同元素
	while (cur1 && cur2 && cur3)
	{
		while (cur1 && cur2)
		{
			// A表的值小于B表,删去这个节点
			if (cur1->data < cur2->data)
			{
				LNode* del = cur1;
				cur1 = cur1->next;
				free(del);
			}
			// A表的值大于B表,B表指针后移
			else if (cur1->data > cur2->data)
			{
				cur2 = cur2->next;
			}
			else if (cur1 && cur2)
			{
				// 判断C表,当C表指针的数据小于A表,C表后移
				while (cur3 && cur3->data < cur1->data)
				{
					cur3 = cur3->next;
				}
				if (cur3)
				{
					// C表数据大于A表,删除A表节点
					if (cur3->data > cur1->data)
					{
						LNode* del = cur1;
						cur1 = cur1->next;
						free(del);
					}
					// 值相等
					else
					{
						// 如果cur1是第一个节点
						if (prev == A)
						{
							prev->next = cur1;
							prev = cur1;
							cur1 = cur1->next;
						}
						// 如果是重复节点,不链入A表
						else if (prev->data == cur1->data)
						{
							LNode* del = cur1;
							cur1 = cur1->next;
							free(del);
						}
						else
						{
							prev->next = cur1;
							prev = cur1;
							cur1 = cur1->next;
						}
					}
				}
			// 链表的工作指针后移
			cur2 = cur2->next;
			cur3 = cur3->next;	
			}
		}
	}
	// A表到尾,尾置空
	if (cur1 == NULL)
		prev->next = NULL;
	// A表未到尾,删除剩余元素
	else
	{
		prev->next = NULL;
		while (cur1)
		{
			LNode* del = cur1;
			cur1 = cur1->next;
			free(del);
		}
	}
}

两个整数数位求和

给定两个用链表表示的整数,每个节点表示一个数位,这些数位是反向存放的,也就是个位排在链表首部
对这两个整数求和,用链表形式返回结果

算法思想

设置carry为当前递归的进位信号,
如果两个链表均不为空。则以L1为根节点,更新其值,并让该节点的next节点(高位数节点)为下次递归返回值,再返回当前节点作为上一个节点(低位节点)的next节点,
如果有一个链表为空,这里假设L2为空,如果递归时,低位节点不存在进位情况,则直接返回L1即可,如果存在进位,就更新L1节点值,并且如果更新L1节点值导致还需要继续进位,则继续递归下去
如果链表全为空,如果此时还需要进位,就返回一个开辟的值位L的新节点,如果不需要进位,直接返回空指针

LinkList addTwoNumbers(LinkList L1, LinkList L2)
{
	// // 如果两个链表都是空的,返回空
	if (L1 == NULL && L2 == NULL)
		return NULL;
	// 如果链表1为空,直接返回链表2
	if (L1 == NULL)
		return L2;
	// 如果链表2为空,直接返回链表1
	if (L2 == NULL)
		return L1;

	// 初始化两个链表的当前节点指针cur1, cur2,和返回链表的头尾指针
	LNode* cur1 = L1, *cur2 = L2, *head = NULL, *tail = NULL;
	// 临时变量,用来保存当前的进位
	int tmp = 0;
	while (cur1 && cur2)
	{
		// 创建新节点保存当前的计算结果
		LNode* ret = (LinkList)malloc(sizeof(LNode));
		// 当前节点的值是两个链表对应节点的和加上进位(tmp)
		ret->data = (cur1->data + cur2->data + tmp) % 10;
		// 如果头节点为空,表示链表为空,设置头尾指针
		if (head == NULL)
		{
			tail = ret;
			head = tail;
		}
		else
		{
			// 如果链表非空,将新节点添加到尾部
			tail->next = ret;
			tail = ret;
		}
		// 计算新的进位
		tmp = (cur1->data + cur2->data + tmp) / 10;
		// 移动到下一个节点
		cur1 = cur1->next;
		cur2 = cur2->next;
	}
	// 如果L2链表长于L1链表,处理L2剩余部分
	if (cur2)
	{
		// 将cur1指向cur2,继续处理
		cur1 = cur2;
	}
	// 处理L1剩余部分
	while (cur1)
	{
		// 创建新节点保存当前的计算结果
		LNode* ret = (LinkList)malloc(sizeof(LNode));
		// 当前节点的值是L1当前节点的值加上进位(tmp)
		ret->data = (cur1->data + tmp) % 10;
		// 更新进位
		tmp = (cur1->val + tmp) / 10;
		// 移动到下一个节点
		cur1 = cur1->next;
		// 将新节点添加到尾部
		tail->next = ret;
		tail = ret;
	}
	// 如果有剩余进位,添加一个新节点表示进位
	if (tmp)
	{
		// 创建新节点保存进位
		LNode* ret = (LinkList)malloc(sizeof(LNode));
		ret->data = tmp;
		// 将进位节点添加到尾部
		tail->next = ret;
		tail = ret;
	}
	// 最后将尾节点的next指针置为空,表示链表结束
	tail->next = NULL;
	// 返回链表的头节点
	reeturn head;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值