C语言实现单链表反转(图文)

C语言实现单链表反转(图文)

据说是一道微软的面试题改编 挺有名的,据说很多人面试时 被要求当场纸写程序基本上都没答出来或者没答完整

本着他人故事不要成为我的事故的原则 ,尝试解一解 把思路分享一下( ̄▽ ̄)"

要完成链表的反转,则需要把后一个节点的指针指向前一个

需要三个指针 p,q,tmp 其中p q用来反转两个节点 tmp用来记住下一个要处理的节点

需要考虑的情况 大体有二 1.从头开始反转 2.从中间任意位置开始反转 当然,还有必不可少的边界检查

中间任意位置开始反序

从最最普遍的情况说起 从中间任意位置反序 大体需要三步 打开冰箱,塞进大象,关上冰箱门

1.预备工作 找到并记录节点

找到想要反转的下标为n的指针 用指针memory记录下它前一个的节点(n-1)的地址 下标为n n+1 n+2的节点位置分别用p.q.temp记录
在这里插入图片描述

2.完成对k个节点反序 (核心操作)

q->next 指向 p 即完成了一次反转 改变了两个节点

而后改变p.q.temp的值 使其指向的节点对应往后移一位 (注意操作的顺序,此时p->next不再指向q 而是指向其上一个节点)

重复这个动作k-1次 就完成了对k个节点的反序

在这里插入图片描述
​ 改变指针 ↑
在这里插入图片描述

​ 移动指针 ↑
C语言实现单链表反转(图文)_第1张图片
​ k-1次操作后 如上图

3.和原有单链表相对接 (很重要,不要内存泄漏)

memory指向的下标为n-1节点 不能再指向下标为n的节点 而需要指向现在的p指向的节点(下标为n+k-1)

下标为n的节点不能再指向下表为n+1的节点 而要指向q指向的节点(下标为n+k)
C语言实现单链表反转(图文)_第2张图片

这一部分的代码为

 NODE *p,*q,*tmp,*memory;
        p=head;
        memory=head;
        for(int i=0; i<n-1; i++)
        {
            memory=memory->next;
        }
        p=memory->next;
        q=p->next;
        tmp=q->next;          //找到并标记节点
        for(int i=0; i<k-1; i++)
        {
            q->next=p;
            p=q;
            q=tmp;
            tmp=tmp->next;
        }                   //完成k-1次反序操作  此时已有k个节点反序
        memory->next->next = q;
        memory->next=p;
        return head;       //对接 返回头指针

从头开始反序

可以参考上一种情况 甚至还要简单一些 不涉及对memory指针操作

有些做法需要额外添加一个空的头节点,我觉得没有必要 (可能是因为我写的是函数 这个时候把p作为头节点返回就行)

照例,源码和图 贴上C语言实现单链表反转(图文)_第3张图片

else if(n==0)
    {
        NODE *p,*q,*tmp;
        p=head;
        q=p->next;
        tmp=q->next;
        for(int i=0; i<k-1; i++)
        {
            q->next=p;
            p=q;
            q=tmp;
            tmp=tmp->next;
        }
        head->next = q;
        return p;
    }

剩余要考虑的几种情况统称都是边界检查问题

1.只反转一个节点 等于不反转,直接返回头节点

2.下标错误 > 链表长度 抛报错下标错误

3.下标+反转的节点个数 > 链表长度 抛报错超出范围

简单,不再说思路

整体代码如下


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

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


NODE*  createlist(int data)  //创建一个节点数量为data链表 返回头节点指针
{
    NODE* head = (NODE*)malloc(sizeof(NODE));
    head->next=NULL;
    head->data=data;
    return head;
}
void showlist(NODE* head)  //用于检查
{
    NODE *p = head;
    int count=0;
    while(p!=NULL)
    {
        printf("index = %d, data = %d\n",count++,p->data);
        p=p->next;
    }
}

NODE* traversal(NODE* head) //遍历链表
{
    NODE *p = head;
    while(p->next!=NULL)
    {
        p=p->next;
    }
    return p;
}

int getlength(NODE* head) //返回节点个数
{
    NODE *p = head;
    int counter=0;
    while(p!=NULL)
    {
        p=p->next;
        counter++;
    }
    return counter;
}

void add(NODE* head,int data)//添加节点
{
    NODE* add;
    add = (NODE*)malloc(sizeof(NODE));
    add->data = data;
    add->next = NULL;
    NODE* p=traversal(head);
    p->next = add;
}

int check_index(NODE* head,int index)//检查下标
{
    int counter=0;
    NODE *p = head;
    while(p->next!=NULL)
    {
        p=p->next;
        counter++;
    }
    return (index>=0&&index<=counter);
}

NODE* reverse(NODE *head)  //从下标为n的节点开始 反转K个节点 
{
    int n,k;
    printf("从下标为n的开始,逆转k个  n:   k:");
    scanf("%d%d",&n,&k);
    if(check_index(head,n)==0)
    {
        printf("下标错误");
        exit(-1);
    }
    else if((n+k)>getlength(head))
    {
        printf("超出范围");
        exit(-1);
    }
    else if (k==1)
    {
        return head;
    }
    else if(n==0)
    {
        NODE *p,*q,*tmp;
        p=head;
        q=p->next;
        tmp=q->next;
        for(int i=0; i<k-1; i++)
        {
            q->next=p;
            p=q;
            q=tmp;
            tmp=tmp->next;
        }
        head->next = q;
        return p;
    }
    else
    {
        NODE *p,*q,*tmp,*memory;
        p=head;
        memory=head;
        for(int i=0; i<n-1; i++)
        {
            memory=memory->next;
        }
        p=memory->next;
        q=p->next;
        tmp=q->next;
        for(int i=0; i<k-1; i++)
        {
            q->next=p;
            p=q;
            q=tmp;
            tmp=tmp->next;
        }
        memory->next->next = q;
        memory->next=p;
        return head;
    }

}


int main() //用于测试的main
{
    NODE *head=createlist(0);
    for (int i = 1; i<10; i++)
        add(head,i);
    showlist(head);
    head=reverse(head);
    showlist(head);
    return 0;
}

你可能感兴趣的:(C语言实现单链表反转(图文))