此处说的是单链表,双链表就没逆置这说法了,循环链表可以按照单链表的操作实现
头插法改变指向
图解
原本链表状态是这样的
想要成为这样
把头部断开,剩下的数据部分再用一遍头插法就好了
具体操作
首先需要两个工作指针,p和remain
p用于指向当前操作结点
remain用于指向剩下待操作的结点
头结点后继指空
首先让p指向remain所指向的结点,也就是剩下结点的第一个,让remain,指向自己的后继
接着让p操作的结点,指向头结点所指,此处为null,不明显,下一轮就明显了
再让头结点指向当前操作结点
明显的第二轮操作
-
p指向remain
-
remain指向自己的后继
-
p指向头结点的后继
-
头结点后继更新为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();
}
运行结果如图
感谢能读到这里,留个赞再走呗