链表,我们都熟知的一种数据结构,今天来讲讲如何将一个链表的顺序倒过来。这是一道比较基础的面试题,但要一次写对还真的不太容易。
首先,链表逆序的操作都是作用在单向列表之中的,这其中的原因就不必细说了。
假定我们有一个链表 [3]->[5]->[1]->[4]->[9] ,链表逆序,其本质就是将每一个节点的next指针倒置过来,使原本指向下一个节点的next指针指向当前节点的上一个节点。具体目的示范如下图。
首先,先从链表的某个节点来看,把它的next指针倒转,我们最少需要知道 3 个节点,分别是:某个节点本身,其前置节点,其后置节点。知道其前置节点,是为了next指针倒转时有节点可以指向;知道其后置节点,是为了当前节点的next完成倒转操作之后,链表逆向操作可以继续进行下去。
那么接下来我们开始进行完整的链表逆向操作:首先先要建立三个临时的节点p1,p2,p3,分别指向头节点,第二个节点,第三个节点。
首先,以p2指向的节点为视角,将p2节点上next指向p1。
然后将p1,p2,p3都向后移一个节点,即p1指向第二个节点,p2指向第三个节点,p3指向第四个节点。继续执行第一步的操作。以此类推,直到p2的值为NULL的时候停止。
最后将原本头节点的next指针指向为NULL。让当前p1所指向的节点为头节结点。
图片示例如下:
1. 将p1,p2,p3分别指向头节点,第二个节点,第三个节点。
2. 将p2节点上next指向p1
3. p1,p2,p3都向后移一个节点
4. 继续执行第一步的操作
5. 继续执行第二步的操作
6. 直到p2为空的时候停止
**7. 此时将原本的头节点指向为NULL
p1所指向的节点为头节结点**
那么代码是如何实现的呢?
static struct Node //定义节点结构体
{
int data;
Node *next;
}
static struct Node head; //定义一个静态临时头节点
void reverseLinkedList() //定义一个函数,进行节点逆序的操作
{
if(head==null || head.next==null) //判断头节点引导的链表是否存在或为单个节点
{
return; //判断为真,推出节点逆序函数
}
Node p1 = head;
Node p2 = head.next;
Node p3 = null; //定义临时节点p1,p2,p3
while(p2 != null) //p2的值不为NULL的时候,
{
p3 = p2.next; //将临时节点p3指向p2的下一个节点
p2.next = p1; //p2的next指针倒置
p1 = p2;
p2 = p3; //p1,p2指针向后移一个节点
}
head.next = null;
head = p1;
}
int main()
{
struct Node node1,node2,node3,node4,node5;
node1->data = 3;
node2->data = 5;
node3->data = 1;
node4->data = 4;
node5->data = 9;
node1->next = node2;
node2->next = node3;
node3->next = node4;
node4->next = node5;
head->next = node1;
//初始化链表
reverseLinkedList(); //逆序链表
//输出结果
struct temp = head;
while(temp != NULL)
{
printf("%d",temp->data);
temp = temp.next;
}
}
链表反转的逻辑本身,都在reverseLinkedList函数当中。在这里我们把链表的头节点作为了静态变量,实际上也可以作为参数传入,只是逻辑上需要一些小小的修改。