此处说的是单链表,双链表就没逆置这说法了,循环链表可以按照单链表的操作实现

头插法改变指向

图解

原本链表状态是这样的
在这里插入图片描述
想要成为这样在这里插入图片描述
把头部断开,剩下的数据部分再用一遍头插法就好了

请添加图片描述

具体操作

首先需要两个工作指针,p和remain
p用于指向当前操作结点
remain用于指向剩下待操作的结点
头结点后继指空
在这里插入图片描述

首先让p指向remain所指向的结点,也就是剩下结点的第一个,让remain,指向自己的后继
在这里插入图片描述
接着让p操作的结点,指向头结点所指,此处为null,不明显,下一轮就明显了
再让头结点指向当前操作结点
在这里插入图片描述

明显的第二轮操作

  1. p指向remain在这里插入图片描述

  2. remain指向自己的后继在这里插入图片描述

  3. p指向头结点的后继在这里插入图片描述

  4. 头结点后继更新为p在这里插入图片描述
    以此循环,直到remain指向为空

代码实现


#include <iostream>
using namespace std;

struct Node {
	int data;
	Node* next;
};//创建结构体——结点

void show(Node* head) {
	head = head->next;
	while (head != nullptr) {
		cout << head->data << '\t';
		head = head->next;
	}
}

void reverse(Node* head) {
	Node* remain, * p, * q;
	remain = head->next;//指向剩下的链表
	head->next = nullptr;//
	while (remain != nullptr) {
		p = remain;//取出剩下结点的第一个
		remain = remain->next;//remain指向自己的后继
		p->next = head->next;//当前结点指向头结点后继
		head->next = p;//更新头结点后继为当前结点
	}
}

int main()
{
	int num;
	Node* first, * p, * rear;
	first = new Node;
	first->next = nullptr;//头结点
	rear = first;

	cout << "请输入数据:   0代表输入结束" << '\n';
	cin >> num;
	while (num != 0) {
		p = new Node;
		p->data = num;
		p->next = nullptr;//新节点

		rear->next = p;
		rear = rear->next;//尾指针重新指向尾部
		cin >> num;
	}//以上是尾插法构建初始链表
	cout << "原链表为:";
	show(first);//显示原链表

	reverse(first);
	cout << "逆置链表为:";
	show(first);//显示新链表
}

注释很详细了,我就不细讲了

运行结果

在这里插入图片描述

更改相邻结点

思考方向

本来链表应该是这样的逻辑结构
在这里插入图片描述

最终应该是这样的逻辑结构
在这里插入图片描述

这样一个工作指针显然是不够的,改变方向后指向原来的通道就断了,毕竟单链表逻辑上是单向的

在链表已有first指针的基础上,引入2个工作指针p、q 在这里插入图片描述

在确保first改变指向(指向p)的时候,q能保存剩余链表的指向(其实还需要一个保存first地址,但不是主要作用)

由于结点1最终指向空,所以我就不拿他具体演示了,直接拿结点2演示,更有普遍性
在操作结点2时,初始状态应该是这样在这里插入图片描述
first结点的指针 指向 p指向的结点(first->next=p)
在这里插入图片描述

p移到first的位置(p=first)
在这里插入图片描述

first移到q的位置(first=q)
在这里插入图片描述

q指向q的后继(q=q->next)在这里插入图片描述
这样一次循环就完成了,循环条件是first指向不为空
这样就确保每个结点都改变了指向

最后头结点指向p所指的结点,first重新指头结点即可

具体代码

首先是结点,数据域我就用int代替了

struct Node{
	int data;
	Node* next;
};//创建结构体——结点

其次是链表类

class LinkList {
private:
	Node* first;
public:
	LinkList();
	LinkList(int a[], int n);
	void reverse();
};
LinkList::LinkList() {
	first = new Node;
	first->next = nullptr;
}
LinkList::LinkList(int a[], int n) {
	first = new Node;
	Node* p = first, * q = first;
	for (int i = 0; i < n; i++) {
		p->next = new Node;
		p = p->next;
		p->data = a[i];
	}
	p->next = nullptr;
	q = q->next;//让p指向第一个结点
	cout << "链表已创建完毕,依次存储:" << endl;
	while (q != nullptr) {
		cout << q->data << '\t';
		q = q->next;
	}
	cout << '\n';
}

最后就是逆序功能的具体实现啦,就是按照上文思路图来写的

void LinkList::reverse() {
	Node* p = nullptr, * q, * a = first;
	first = first->next;
	q = first->next;
	while (1) {
		first->next = p;
		p = first;
		first = q;
		if (first == nullptr) break;
		q = q->next;
	}
	a->next = p;
	first = a;//逆序已全部完成,以下为遍历输出
	cout << "已完成逆序,现在链表存储数据顺序为:" << endl;
	Node* b = first->next;
	while(b != nullptr) {
		cout << b->data << '\t';
		b = b->next;
	}
}

值得一提的是,我这里判断语句并没有放进while循环开头,原因在于最后一次操作时,q已经指向空,再执行q=q->next;就会发生异常在这里插入图片描述
主函数用1 2 3 4 5测试的

int main() {
	int a[5] = { 1,2,3,4,5 };
	LinkList l(a, 5);
	l.reverse();
}

运行结果如图在这里插入图片描述
感谢能读到这里,留个赞再走呗在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐