B. DS单链表--结点交换

题目描述

用C++实现含头结点的单链表,然后实现单链表的两个结点交换位置。
注意不能简单交换两个结点包含数据,必须通过修改指针来实现两个结点的位置交换
交换函数定义可以参考:
swap(int pa, int pb) //pa和pb表示两个结点在单链表的位置序号
swap (ListNode * p, ListNode * q) //p和q表示指向两个结点的指针

输入

第1行先输入n表示有n个数据,接着输入n个数据
第2行输入要交换的两个结点位置
第3行输入要交换的两个结点位置

输出

第一行输出单链表创建后的所有数据,数据之间用空格隔开
第二行输出执行第1次交换操作后的单链表数据,数据之间用空格隔开
第三行输出执行第2次交换操作后的单链表数据,数据之间用空格隔开
如果发现输入位置不合法,输出字符串error,不必输出单链表

输入样例

5 11 22 33 44 55
1 4
2 6

输出样例

11 22 33 44 55 
44 22 33 11 55 
error

struct ListNode 定义结构体

是为了表示链表中的每一个结点

struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};
  • int val:链表的每个节点都需要存储一个数据元素
  • ListNode* next:是一个指针。指向链表中的下一个节点。通过它,将多个节点连接起来形成链表
  • ListNode(int x) : val(x), next(nullptr):构造函数,用于初始化ListNode中的变量val,next

val(x):将传入的参数 x 赋值给结点的 val 成员变量。
next(nullptr):将指针 next 初始化为 nullptr(空指针),表明该结点当前没有指向下一个结点。

构造函数让创建结点的过程变得简洁。例如,当你写 new ListNode(data) 时,它会自动调用这个构造函数来初始化结点的值和指针。


ListNode* createList(int n) 创建一个包含n个元素的单链表

ListNode* createList(int n) {
    ListNode* head = new ListNode(0); 
    ListNode* tail = head;
    for (int i = 0; i < n; i++) {
        int data;
        cin >> data;
        tail->next = new ListNode(data); // 添加新结点
        tail = tail->next;
    }
    return head;
}
  • ListNode* head = new ListNode(0):创建头结点,赋予初始值(可帮助区分头结点和其他结点),head 指向这个头结点
  • ListNode* tail = head:追踪当前链表的尾部,方便在尾部添加新结点
  • tail->next = new ListNode(data):添加新结点到链表尾部。tail->next指向新创建的结点
  • tail = tail->next:移动到链表的最后一个结点,即刚刚创建的结点。通过不断循环,新结点继续添加到链表的尾部
  • return head:链表创建完成,返回链表的头结点指针

创建完后,返回一个指向单链表头结点的指针,返回类型是 ListNode*

单链表的结构是由一系列结点通过指针连接在一起的。每个结点只知道它的下一个结点在哪里。因此,如果你想访问整个链表,必须从头结点开始

返回 head 以后,实际的链表数据从head->next 开始


void printList(ListNode* head) 输出单链表

void printList(ListNode* head) {
    ListNode* current = head->next; 
    while (current) {
        cout << current->val << " ";
        current = current->next;
    }
    cout << endl;
}
  • ListNode* head:接收链表的头结点
  • ListNode* current = head->next:链表的第一个存储数据的结点

bool swapNodes(ListNode* head, int pos1, int pos2) 交换两个结点的位置

bool swapNodes(ListNode* head, int pos1, int pos2) {
    if (pos1 == pos2) return true; // 如果两个位置相同,不需交换

    ListNode* prev1 = nullptr, * prev2 = nullptr, * node1 = head, * node2 = head;

    // 查找第一个位置的结点及其前驱
    for (int i = 0; i < pos1 && node1; i++) {
        prev1 = node1;
        node1 = node1->next;
    }

    // 查找第二个位置的结点及其前驱
    for (int i = 0; i < pos2 && node2; i++) {
        prev2 = node2;
        node2 = node2->next;
    }

    // 如果有任何一个位置越界,则返回false,交换失败
    if (!node1 || !node2) return false;

    // 如果两个位置都有效,进行交换
    prev1->next = node2;
    prev2->next = node1;

    // 交换 next 指针
    ListNode* temp = node1->next;
    node1->next = node2->next;
    node2->next = temp;

    return true;
}
  • 初始化四个指针变量:pre1,pre2存储要交换的两个结点的前驱结点,初始为nullptrnode1,node2存储要交换的两个结点,初始为头结点
  • 两个for循环:找到序号为pos1,pos2的结点以及它们的前驱结点。

如果输入的位置序号 pos1 或 pos2 超出了链表的实际长度,那么在遍历链表时,node1 或 node2 将会变成 nullptr。在这种情况下,如果不检查 node1 和 node2 是否为 nullptr,那么在尝试交换结点时就会出现问题

  • prev1->next = node2:更新前驱结点的next指针,以指向新结点的位置
  • node1->next = node2->next:交换两个结点的next指针

完整代码

#include<iostream>
using namespace std;

struct ListNode {
	int val;
	ListNode* next;
	ListNode(int x) :val(x), next(nullptr){}
};

ListNode* List(int n) {
	ListNode* head = new ListNode(0);
	ListNode* tail = head;
	for (int i = 0; i < n; ++i) {
		int num;
		cin >> num;
		tail->next = new ListNode(num);
		tail = tail->next;
	}
	return head;
}

void printList(ListNode* head) {
	ListNode* current = head->next;
	while (current) {
		cout << current->val << ' ';
		current = current->next;
	}
	cout << endl;
}

bool SwapNode(ListNode* head, int pos1, int pos2) {
	if (pos1 == pos2)return true;
	ListNode* f1 = nullptr, * f2 = nullptr, * node1 = head, * node2 = head;

	//找到前结点和当前结点
	for (int i = 0; i < pos1&&node1; ++i) {
		f1 = node1;
		node1 = node1->next;
	}
	for (int i = 0; i < pos2&&node2; ++i) {
		f2 = node2;
		node2 = node2->next;
	}
	//如果越界
	if (!node1 || !node2)return false;

	f1->next = node2;
	f2->next = node1;

	ListNode* tep = node1->next;
	node1->next = node2->next;
	node2->next = tep;
	return true;
}

void deleteList(ListNode* head) {
	ListNode* current = head;
	while (current) {
		ListNode* next = current->next;
		delete current;
		current = next;
	}
}

int main() {
	int n;
	cin >> n;
	ListNode* head = List(n);
	printList(head);

	int p1, p2;
	cin >> p1 >> p2;
	if (!SwapNode(head, p1, p2)) {
		cout << "error\n";
		return 0;
	}
	printList(head);

	cin >> p1 >> p2;
	if (!SwapNode(head, p1, p2)) {
		cout << "error\n";
		return 0;
	}
	printList(head);
	deleteList(head);
	return 0;
}
DS单链表是一种线性数据结构,它由若干个节点组成,每个节点包括数据域和指针域,其中数据域用于存储数据,指针域用于指向下一个节点。DS单链表的存储结构如下: ``` typedef struct ListNode { int val; struct ListNode *next; } ListNode; ``` 其中,val表示节点存储的数据,next表示指向下一个节点的指针。 DS单链表的基本操作包括:创建、插入、删除、查找、遍历等。 1. 创建 创建DS单链表的方法有多种,例如头插法、尾插法等。其中,头插法的实现代码如下: ``` ListNode* createList(int arr[], int n) { ListNode *head = NULL; for (int i = 0; i < n; i++) { ListNode *node = (ListNode*)malloc(sizeof(ListNode)); node->val = arr[i]; node->next = head; head = node; } return head; } ``` 2. 插入 DS单链表的插入操作包括在指定位置插入节点和在末尾插入节点。其中,指定位置插入节点的实现代码如下: ``` void insert(ListNode *head, int val, int pos) { ListNode *node = (ListNode*)malloc(sizeof(ListNode)); node->val = val; ListNode *p = head; for (int i = 1; i < pos && p != NULL; i++) { p = p->next; } if (p == NULL) { return; } node->next = p->next; p->next = node; } ``` 3. 删除 DS单链表的删除操作包括删除指定位置的节点和删除指定值的节点。其中,删除指定位置的节点的实现代码如下: ``` void delete(ListNode *head, int pos) { ListNode *p = head; ListNode *q = NULL; for (int i = 1; i < pos && p != NULL; i++) { q = p; p = p->next; } if (p == NULL) { return; } if (q == NULL) { head = head->next; } else { q->next = p->next; } free(p); } ``` 4. 查找 DS单链表的查找操作包括查找指定位置的节点和查找指定值的节点。其中,查找指定值的节点的实现代码如下: ``` ListNode* find(ListNode *head, int val) { ListNode *p = head; while (p != NULL) { if (p->val == val) { return p; } p = p->next; } return NULL; } ``` 5. 遍历 DS单链表的遍历操作包括正向遍历和反向遍历。其中,正向遍历的实现代码如下: ``` void traverse(ListNode *head) { ListNode *p = head; while (p != NULL) { printf("%d ", p->val); p = p->next; } } ``` 以上就是DS单链表的存储结构与操作的介绍。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值