单链表(Listnode)

一、引言

“大江东去,浪淘尽,千古风流人物。”一想起三国就不得不谈到几大以少胜多的战役,官渡之战、赤壁之战、夷陵之战。今天我们就以赤壁之战为模版讲述链表。面对孙刘联盟曹操采纳了“铁索连船”来克服北方人水土不服的弱点。链表的应用场景正好可以运用到“铁索连船”中去。假如诸位魏国的主公在“东风不与周郎便”的情况下又该如何发挥自己的旷世奇才。

二、链表的主要内容

在这危机四伏的江湖中,主公英明神武的领导、关于战场随机应变的调度可是决定战争胜利的关键因素。首先我们要考虑铁索连船的添加船只来进行排兵布阵,也就是链表的头插和尾插。但最重要的是要有船(结点),当然我们可以先创建一个结构体变量来存储变量的值和下一个元素的地址,再进行创建新的节点头插尾插操作,由于在函数中创建局部变量存储局部节点,一出函数就被系统回收了,所以我们要运用到合适的创建链表的工具,也就是薄利多销且效率至上的造船商。也就是运用malloc函数进行动态内存管理创建一个新的节点,并将他们自动连串。

二.1.链表的插入

头插:顾名思义就是将新创建的节点放在链表的开头。具体操作:将创建的新节点中结构体存储的地址修改为头结点自身的地址,再令头结点等于头插过来的新节点。具体代码如下:

void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* add = (SLTNode*)malloc(sizeof(SLTNode));
	add->data = x;
	add->next = *pphead;
	*pphead = add;
}

尾插:顾名思义就是将新创建的节点放在链表的末尾。具体操作:先将链表的头结点先保存起来,再令其走到空节点(假设链表的末尾为空)的前一个节点,将新创建的节点自身的地址存储入空节点(假设链表的末尾为空NULL)的前一个节点,再将头结点复原,具体代码如下:

void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	assert(pphead != NULL);
	SLTNode* mid = *pphead;
	if (mid == NULL)
	{
		mid = (SLTNode*)malloc(sizeof(SLTNode));
		//SLTBuyNode(*pphead,x);
		mid->data = x;
		mid->next = NULL;
		assert(mid != NULL);
		exit ;
	}
	else
	{
		while (mid->next != NULL)
		{
			mid = mid->next;
		}
		mid->next = (SLTNode*)malloc(sizeof(SLTNode));
		mid->next->data = x;
		mid->next->next = NULL;
	}
}

鉴于链表有可能为空,所以先进行判空再决定是创建新节点,还是尾插。

指定位置之后插入:还是先保存头结点,再走到指定位置,将指定位置后的节点保存下来,先将创建节点中结构体存储的指针等于指定位置后节点自身的地址,最后再令指定位置节点的指针等于新

创建节点自身地址。最后再将头结点复原。具体代码如下:

void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos != NULL);
	SLTNode* add = (SLTNode*)malloc(sizeof(SLTNode));
	add->data = x;
	add->next = pos->next;
	pos->next = add;
}
这些就是在战争备战阶段建造铁索连船,在局势复杂的战场中兵无常势、水无常形,想要取得胜利必须灵活多变。
二.2.链表的删除

在战争中一定会有战船受损无法参加战斗所以就需要舍小保大,那铁索连船中一定需要“裁员”。那链表中的部分节点也需要删除。

头删:先存储头节点,头节点往后走一位,再将原头节点释放掉。具体代码如下:

void SLTPopFront(SLTNode** pphead)
{
	assert(pphead != NULL && (*pphead) != NULL);
	SLTNode* mid = (*pphead);
	(*pphead) = (*pphead)->next;
	free(mid);
}

尾删:先保存头结点,令头结点走到尾(NULL)的前两个个节点处,释放该处的下一个节点,再将该处结构体中的指针置为NULL变成新的船尾。

void SLTPopBack(SLTNode** pphead)
{
	assert(pphead != NULL&&(*pphead) != NULL );
	SLTNode* del = *pphead;
	while (del->next->next != NULL)
	{
		del = del->next;
	}
	free(del->next);
	del->next = NULL;
}
#include <iostream> #include <vector> #include <string> using namespace std; // 单链表节点 struct ListNode { string val; ListNode* next; ListNode(const string& x) : val(x), next(nullptr) {} }; // 创建带头结点的单链表 ListNode* createList(const vector<string>& data) { ListNode* head = new ListNode(""); // 头结点 ListNode* tail = head; for (const string& val : data) { ListNode* node = new ListNode(val); tail->next = node; tail = node; } return head; } // 获取链表长度(不含头结点) int getLength(ListNode* head) { int len = 0; ListNode* curr = head->next; while (curr) { len++; curr = curr->next; } return len; } // 获取第 pos 个节点的前驱和该节点本身 pair<ListNode*, ListNode*> getNodeAt(ListNode* head, int pos) { ListNode* prev = head; ListNode* curr = head->next; for (int i = 1; i < pos && curr; ++i) { prev = curr; curr = curr->next; } return make_pair(prev, curr); } // 移动节点:将 current_pos 的节点移到 target_pos bool moveNode(ListNode* head, int current_pos, int target_pos) { int n = getLength(head); // 检查位置合法性 if (current_pos < 1 || current_pos > n || target_pos < 1 || target_pos > n) { return false; } if (current_pos == target_pos) return true; // 相同位置无需操作 // 获取待移动节点及其前驱 auto [curr_prev, curr_node] = getNodeAt(head, current_pos); // 从原位置摘下该节点 curr_prev->next = curr_node->next; // 获取目标位置的前驱节点 auto [tar_prev, tar_node] = getNodeAt(head, target_pos); // 将节点插入到 target_pos 位置 curr_node->next = tar_prev->next; tar_prev->next = curr_node; return true; } // 输出链表:每个元素后都加空格(包括最后一个) void printList(ListNode* head) { ListNode* curr = head->next; while (curr) { cout << curr->val << " "; // 注意:每个后面都有空格 curr = curr->next; } cout << endl; } // 释放链表内存 void deleteList(ListNode* head) { while (head) { ListNode* temp = head; head = head->next; delete temp; } } int main() { int n; cin >> n; vector<string> data(n); for (int i = 0; i < n; ++i) { cin >> data[i]; } int t; cin >> t; // 创建链表 ListNode* head = createList(data); // 输出原始链表 printList(head); // 执行 t 次移动操作 while (t--) { int cur, tar; cin >> cur >> tar; if (!moveNode(head, cur, tar)) { cout << "error" << endl; } else { printList(head); } } // 释放内存 deleteList(head); return 0; } /********************************************************************** Problem: 1658 User: 202400502126 Language: C++ Result: AC Time:12 ms Memory:2224 kb **********************************************************************/ 把里面的变量全部改成拼音缩写
10-28
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值