链表反转详解图解

  • Post author:
  • Post category:其他


在实现反转之前,先回顾链表操作的一些重点。

现链表节点是以下形式:

struct Node {
	int data;
	Node* next;
};

解决链表问题一定要理解深刻,一些要注意的点:

链表中每一个节点都是物理内存中实际存在的,物理节点本身是固定不变的,给定了地址就在那个地址中不会转移、变化等,链表之所以能够添加,删除,反转等,本质是指向这些物理节点的指针节点在移动,即给物理节点赋予的指针是变化的,而我们进行链表操作实际上是操作这些指针节点。

拿一个例子做说明:假设已经建立一个链表,名为list,它也代表链表的头结点:

蓝色方框表示的是物理内存中实际存在的节点,我在方框下方标注了他们所处的内存地址(橙色)。我用名为list的指针(绿色方框)表示指向这片具有逻辑顺序关系的链表。

理解1:一旦链表已经形成,通过对头节点操作,可以索引出链表中所有的节点,并且是基于箭头所指方向进行索引的!也就是说只能说单向的,箭头的含义其实就在于这里-单向。拿这个链表再作解释:

通过

list = list->next

List所指向的节点到了值为2的物理内存上。这样以后,没有建立其他辅助节点指针的条件下,List就再也不具备能力回到值为1的那个物理节点上,这就是单向的意义。List继续可以往后索引。

那么对于链表反转,我们想要实现的就是从上面的链表形式转换成如下的形式,什么改变了,很明显,箭头反过来了。箭头变了,意味着next指向的地址也要反过来!

先给出实现代码:

Node* ReverseList(Node* list)
{
	Node* tmpNode = list;
	Node* preNode = nullptr;
	while (tmpNode)
	{
		Node* nextNode = tmpNode->next;
		tmpNode->next = preNode;
		preNode = tmpNode;
		tmpNode = nextNode;
	}
	list = preNode;
	return list;
}

一条一条语句分析:

Node* tmpNode = list;

增加一个辅助指针,也可以说辅助节点吧,为了方便,后面提的“节点”都表示为“指向节点的指针”,区分物理节点。

Node* preNode = nullptr;

进入循环中依次索引链表中的节点。

1:Node* nextNode = tmpNode->next;

2:tmpNode->next = preNode;

3-4:

preNode = tmpNode;

tmpNode = nextNode;

第二次:

Node* nextNode = tmpNode->next;

tmpNode->next = preNode;

此时发现,箭头反过来了,这正不是我们想要的,tmpNode和preNode继续往后推,

preNode = tmpNode;

tmpNode = nextNode;

现在要做的不就把tmpNode->next指向preNode不就完事了

Node* nextNode = tmpNode->next;

tmpNode->next = preNode;

到这里基本上结束了,把preNode赋给list,完成。



版权声明:本文为maoni99999原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。