链表的就地逆置(多图详解)

链表的就地逆置

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

思考方向

本来链表应该是这样的逻辑结构
链表的就地逆置(多图详解)_第1张图片

最终应该是这样的逻辑结构
链表的就地逆置(多图详解)_第2张图片

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

在链表已有first指针的基础上,引入2个工作指针p、q 链表的就地逆置(多图详解)_第3张图片

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

由于结点1最终指向空,所以我就不拿他距离演示了,直接拿结点2演示,更有普遍性
在操作结点2时,初始状态应该是这样链表的就地逆置(多图详解)_第4张图片
first结点的指针 指向 p指向的结点(first->next=p)
链表的就地逆置(多图详解)_第5张图片

p移到first的位置(p=first)
链表的就地逆置(多图详解)_第6张图片

first移到q的位置(first=q)
链表的就地逆置(多图详解)_第7张图片

q指向q的后继(q=q->next)链表的就地逆置(多图详解)_第8张图片
这样一次循环就完成了,循环条件是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;就会发生异常链表的就地逆置(多图详解)_第9张图片
主函数用1 2 3 4 5测试的

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

运行结果如图链表的就地逆置(多图详解)_第10张图片
感谢能读到这里,留个赞再走呗链表的就地逆置(多图详解)_第11张图片

你可能感兴趣的:(数据结构,链表,单链表,算法)