试写一算法,对单链表进行逆置

NOTICE: 本篇代码是按照源码的书写顺序所写,复制之后可直接运行。

环境: vscode

题目:

试写一算法,对单链表进行逆置

分析:

单链表的逆置需要设置两个指针,第一个进行遍历单链表;第二个进行节点的反向连接。

单链表的逆置其实就是反复利用删除插入操作。

主意:本题所说的逆置不能开辟新的内存空间,这样一来就不能创建一个新的表然后利用尾插法进行“逆置”了。

代码:

初始化单链表:

#include<stdio.h>
#include<stdlib.h>

#define OK 1
#define ERROR 0

typedef int ElemType;
typedef int Status;

typedef struct LNode
{
    ElemType data;
    LNode *next;
}LNode, *LinkList;

Status InitList(LinkList &L)
{   // 初始化单链表 L
    L = (LNode*)malloc(sizeof(LNode));
    L->next = NULL;

    return OK;
}//InitList

生成单链表:

Status CreateList(LinkList &L, int e)
{   // 创建单链表 L
    LinkList p = L;
    while(p->next)
        p = p->next;
    LinkList temp = (LinkList)malloc(sizeof(LNode));
    temp->data = e;
    temp->next = NULL;
    p->next = temp;

    return OK;
}//CreateList

打印单链表:

Status DispList(LinkList &L)
{   // 打印单链表 L
    LinkList p = L->next;
    while(p)
    {
        printf("%d\t", p->data);
        p = p->next;
    }
    return OK;
}//DispList

逆置:

Status ListOppose(LinkList &L)
{   // 将带表头节点的单链表逆置
    LinkList q, p, s;
    p = L;
    p = p->next;
    L->next = NULL;
    while(p) // 因为 while 中有 p = p->next 所以终止条件不用写成 p->next
    {
        q = p;
        p = p->next;
        q->next = L->next; // q 节点指向现在的 L 的首元结点。这一行加上下一行相当于一个插入操作
        L->next = q;
    }

    return OK;
}//ListOppose

方法二:

Status ListOppose(LinkList &L)
{   // 将带表头节点的单链表逆置
    LinkList q, p, s;
    p = L->next;
    q = p->next;
    s = q->next;
    p->next = NULL;
    while(s->next)
    {
        q->next = p;
        p = q;
        q = s;
        s = s->next;
    }
    // 将尾结点连接到原表的首元结点
    q->next = p;
    s->next = q;
    L->next = s;
    
    return OK;
}//ListOppose

主函数:

int main()
{
    int i;
    LinkList L;
    InitList(L);
    for(i=1; i<=10; i++)
        CreateList(L, i);
    printf("\n创建的单链表为:\n");
    DispList(L);
    printf("\n逆置后的单链表为:\n");
    ListOppose(L);
    DispList(L);

    return OK;
}

创建好的单链表为:

试写一算法,对单链表进行逆置

(PS: 画图太难了!!!!!我透!)

其中,ListOppose() 函数中(第一种方法):

  1. p = L, 即:使 p 指向 L 的头结点
  2. p = p->next, 即:p 向后移动一个位置。这是为了给另一个用来做反向连接的变量 q 挪地方
  3. L->next = NULL, 将表 L 掐断,变成如下图所示:试写一算法,对单链表进行逆置

      4. 第一次循环:

               q = p; p = p->next;  这两行就是把 q 指向 p,然后将 p 向后移动到下一个节点:

                试写一算法,对单链表进行逆置

         q->next = L->next;  L->next = q;  这两行就是进行插入,即:将 q 所指的节点插入到现在的表 L 的头结点和首元结点中间:

 

试写一算法,对单链表进行逆置

如果搞不清楚 q 和 p 所指向的节点的话,可以在程序里打印 q->data 或者 p->data,这样就能很清楚的看到每次循环 q 和 p 所指节点。我复盘的时候就蒙圈了,不晓得 q 先指向哪个节点,所以我打印了 q->data:

试写一算法,对单链表进行逆置

然后看到运行结果如下图:

试写一算法,对单链表进行逆置

可以很清楚的看到,q 先指向首元结点。

第二次循环:

q = p; p = p->next; q 向后移,p 也向后移;

试写一算法,对单链表进行逆置

q->next = L->next; L->next = q; 将 data 域为 2 的节点插入到首元结点之前:

试写一算法,对单链表进行逆置

第三次循环:

q = p; p = p->next; q->next = L->next; L->next = q; 将 data 域为 3 的加点插入到首元结点的前边:

试写一算法,对单链表进行逆置

以此类推,到最后一次循环结束的时候:

试写一算法,对单链表进行逆置

没错,p 指向空,此时跳出循环,但是整个单链表的逆置也已经完成了。

运行结果示意图:

试写一算法,对单链表进行逆置

THE END!

上一篇:力扣:搜索插入位置


下一篇:力扣LeetCode经典算法 调整数组顺序使奇数位于偶数前面