数据结构期末拯救计划:单链表

1.首先明确一下单链表的特点,单链表的数据不像顺序表那样在物理空间上连续,而是分布在内存的各个地方,相较于顺序表随机访问的便捷性,链表的增删改更为方便,现在来看看例题

2.双指针算法的典型应用:多项式相加

多项式相加

【问题描述】编写一个程序用单链表存储多项式,并实现两个一元多项式A与B相加的函数。A,B刚开始是无序的,A与B之和按降序排列。例如:
                        多项式A:  1.2X^0  2.5X^1  3.2X^3  -2.5X^5
                        多项式B:  -1.2X^0  2.5X^1  3.2X^3   2.5X^5   5.4X^10
                        多项式A与B之和:5.4X^10  6.4X^3  5X^1
【输入形式】第一行第一个数据n代表多项式的总项数,后面的2*n个数据,每一对代表对应的某一项的系数和指数,第二行类似,第三行的数据x要查询第几项
【输出形式】多项式中某一项的系数与指数,系数保留一位小数

【输入样例】
4 1.2 0 2.5 1 3.2 3 -2.5 5
5 -1.2 0 2.5 1 3.2 3 2.5 5 5.4 10
2

【输出样例】

6.4 3

【样例说明】
第一个多项式的系数与指数对,以空格隔开
第二个多项式的系数与指数对,以空格隔开
输出第2项的系数与指数,系数与指数间用空格隔开,系数保留一位小数

【评分标准】必须用链表实现

这道题的方法非常典型,首先将数据存在两个链表上,根据双指针的算法,两个链表都需要进行排序以实现单调性,然后同时移动双指针,第一个链表的系数值大于第二个链表的系数值或者相反,则把该节点后插到新链表的后面,如果等于就相加并同时移动,循环结束条件为一个表遍历完,后续只需把没有遍历完的表接到新链表后面即可

#include<iostream>
#include<iomanip>
#include<malloc.h>
using namespace std;
typedef struct Polynode {
	double coef;
	int exp;
	struct Polynode* next;
}Polynode, * Polylist;

void Create(Polylist& head)
{
	Polynode* s, * tail;
	head = new Polynode;
	tail = head;
	int n;
	cin >> n;
	while (n--)
	{
		double c;
		int e;
		cin >> c >> e;
		s = new Polynode;
		s->coef = c;
		s->exp = e;
		tail->next = s;
		tail = s;
	}
	tail->next = NULL;
}

void output(Polylist& L, int x)
{
	Polynode* p = L;
	for (int i = 0; i < x; i++)
	{
		p = p->next;
	}
	cout << fixed << setprecision(1) << p->coef << " ";
	cout << p->exp;
}

void Polyadd(Polylist& polya, Polylist& polyb)
{
	int flag = 0;
	Polynode* p, * q, * tail;
	double sum;
	p = polya->next;
	q = polyb->next;
	tail = polya;
	while (p && q)
	{
		if (p->exp < q->exp)
		{
			tail = p;
			p = p->next;
		}
		else if (p->exp == q->exp)
		{
			sum = p->coef + q->coef;
			if (sum != 0)
			{
				if (flag == 0)
				{
					p->coef = sum;
					tail = p;
					p = p->next;
					q = q->next;
				}
				else
				{
					q->coef = sum;
					tail = q;
					q = q->next;
					p = p->next;
				}
			}
			else
			{
				p = p->next;
				tail->next = p;
				q = q->next;
			}
		}
		else
		{
			tail->next = q;
			tail = q;
			q = q->next;
			flag++;
		}
	}
	if (p != NULL)
		tail->next = p;
	else
		tail->next = q;
}

void sort(Polylist& L)
{
	Polynode* p, * q;
	double t1;
	int t2;
	for (p = L->next; p != NULL; p = p->next)
	{
		for (q = p->next; q != NULL; q = q->next)
		{
			if (p->exp < q->exp)
			{
				t1 = p->coef;
				p->coef = q->coef;
				q->coef = t1;
				t2 = p->exp;
				p->exp = q->exp;
				q->exp = t2;
			}
		}
	}
}

void sort1(Polylist& L)
{
	Polynode* p, * q;
	double t1;
	int t2;
	for (p = L->next; p != NULL; p = p->next)
	{
		for (q = p->next; q != NULL; q = q->next)
		{
			if (p->exp > q->exp)
			{
				t1 = p->coef;
				p->coef = q->coef;
				q->coef = t1;
				t2 = p->exp;
				p->exp = q->exp;
				q->exp = t2;
			}
		}
	}
}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	Polylist polya, polyb;
	Create(polya);
	sort1(polya);
	Create(polyb);
	sort1(polyb);
	Polyadd(polya, polyb);
	sort(polya);
	int x;
	cin >> x;
	output(polya, x);
	return 0;
}


3.正难则反:找倒数第k个节点

输出单链表倒数第K个结点值

【问题描述】输入一个单向链表,输出该链表中倒数第k个结点,链表的最后一个结点是倒数第1个节点。


【输入形式】输入第一位为K值,其后接一串以空格分隔的整型值,以0结束输入。
【输出形式】输出为倒数第K个结点的值,若无,则输出Not Found


【样例输入】3 13 45 54 32 1 4 98 2 0
【样例输出】4
【样例说明】K值为3,则输出链表倒数第3个结点的值,为4;数据输入间以空格隔开
【评分标准】本题要综合输出正确性及使用的数据结构。需由输入数据构建单链表。不使用链表的将不得分。

这道题就是传说中的正难则反,找倒数第k个节点,就是不处理倒数第k个节点,处理正数第n-k个节点

#include <stdio.h>  
#include <stdlib.h>  

// 定义链表节点结构体  
typedef struct ListNode {
    int val;
    struct ListNode* next;
} ListNode;

// 创建链表节点  
ListNode* createNode(int val) {
    ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
    if (!newNode) {
        perror("Memory allocation failed");
        exit(EXIT_FAILURE);
    }
    newNode->val = val;
    newNode->next = NULL;
    return newNode;
}

// 向链表尾部添加节点  
void appendNode(ListNode** head, int val) {
    ListNode* newNode = createNode(val);
    if (*head == NULL) {
        *head = newNode;
    }
    else {
        ListNode* current = *head;
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = newNode;
    }
}

// 找到链表的倒数第k个节点  
ListNode* findKthToTail(ListNode* head, int k) {
    if (head == NULL || k <= 0) {
        return NULL;
    }
    ListNode* fast = head, * slow = head;
    // 首先让快指针前进k步  
    for (int i = 0; i < k - 1; ++i) {
        if (fast->next != NULL) {
            fast = fast->next;
        }
        else {
            // 如果快指针在前进k步后到达链表尾部,说明k大于链表长度  
            return NULL;
        }
    }
    // 然后快慢指针同时前进,直到快指针到达链表尾部  
    while (fast->next != NULL) {
        fast = fast->next;
        slow = slow->next;
    }
    // 此时慢指针指向倒数第k个节点  
    return slow;
}

int main() {
    int k, val;
    ListNode* head = NULL;

    // 读取K值  
    scanf("%d", &k);

    // 读取链表值,以0为结束标志  
    while (scanf("%d", &val) == 1 && val != 0) {
        appendNode(&head, val);
    }

    // 查找倒数第k个节点  
    ListNode* kthNode = findKthToTail(head, k);

    // 输出结果  
    if (kthNode) {
        printf("%d\n", kthNode->val);
    }
    else {
        printf("Not Found\n");
    }

    // 释放链表内存  
    ListNode* current = head;
    while (current) {
        ListNode* temp = current;
        current = current->next;
        free(temp);
    }

    return 0;
}

4.环形链表的经典问题:约瑟夫问题

.约瑟夫环问题

【问题描述】用不带头结点的单向循环链表解决约瑟夫环问题。

【输入形式】输入n和m的值,其中n为总人数,m为报数的密码

【输出形式】胜利者编号,也就是最后一个离开队伍的人

【样例输入】6 4

【样例输出】5

 环形链表的约瑟夫问题-CSDN博客  看这个

最后来看一看重中之重,各种链表的基本操作

复习1:单链表-CSDN博客

复习2:带头双向链表-CSDN博客

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值