单项链表的逆置


源代码

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

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

struct list *create_list()//建立一个节点
{
    //struct list *p = malloc(sizeof(struct list));
    //p->data = 0;
    //p->next = NULL;
    //return p;
    return (struct list *)calloc(sizeof(struct list), 1);
}

void traverse(struct list *ls)//循环遍历链表
{
    struct list *p = ls;
    while(p)
    {
        printf("%d\n", p->data);
        p = p->next;
    }
}

//第一个参数是链表的首节点,第二个参数是插入的位置,第三个参数是插入的值
struct list *insert_list(struct list *ls, int n, int data)//在指定位置插入元素
{
    struct list *p = ls;
    while (p && n--)
    {
        p = p->next;
    }

    //假设n大于链表里node的数量,那么下面的条件成立
    if (p == NULL)//n大于链表节点数量,代表指定位置是个无效的位置
        return NULL;

    struct list *node = create_list();//创建一个新的节点
    node->data = data;
    node->next = p->next;
    p->next = node;
    return node;

}

void nizhi(struct list *ls) //逆置链表
{
    struct list *p1 = ls;
    struct list *p2 = ls->next;
    struct list *p3;
    struct list *last = ls->next;
    while (p2)
    {
        p3 = p2->next;
        p2->next = p1;
        p1 = p2;
        p2 = p3;
        //printf("%d, %d\n", p1->data, p2->data);
    }
    last->next = NULL;
    ls->next = p1;
}

int main(void)
{
    struct list *first = create_list();//创建了一个首节点
    int i;
    for(i = 1; i < 10; i++)
    {
        insert_list(first, 0, i);
    }

    insert_list(first, 50, 100);
    //clean_list(first);
    traverse(first);
    nizhi(first);
    printf("------------\n");
    traverse(first);
    free(first);
    return 0;
}

解析
这里写图片描述
上图是逆置前和逆置后指针指向的位置变化

首先要把先把前两个元素单独拿出来分别放到p1,p2里面去

p3 = p2->next;//存一下后一个元素的位置,以便p2向后移动的时候有下一个元素地址可以使用
p2->next = p1;//就是让后一个元素指向前一个元素,
p1 = p2;    //p1往后移动一个元素
p2 = p3;    //p2往后移动一个元素
至此,已经把一个元素的指针方向改变,并且p1,p2两个元素全部往后移动了一个元素
那使用一个while循环就可以把剩下的元素全部指向前一个
以p2为终止变量,因为当p2=p3的时候,p2已经是当前改变指针方向元素的next了,如果它是NULL,说明已经循环到了指针的末尾
while(p2) {
    p3 = p2->next;
    p2->next = p1;
    p1 = p2;
    p2 = p3;
}
此时,链表中的除首元素的外的元素已经全部指向的前一个元素,但是逆置前的第二个元素,也就是你逆置后的最后一个元素,也指向了首元素,那这就形成了一个环路。所以要把这个元素的next置为NULL。
但是逆置之后,已经没有办法得到这个元素的地址了,所以要在逆置前就把这个元素的地址存下来`struct list *last = ls->next;`
然后在逆置之后在把它指向NULL`last->next = NULL`;
切记,不能再逆置之前就把它指向NULL,因为那样,两边就只剩两个元素了。所以逆置的整个过程如下
void nizhi(struct list *ls)
{
    if (ls->next == NULL || ls->next->next == NULL) //如果两边只有一个或者两个元素,逆置就没有意义,返回
        return ;

    struct list *p1 = ls;
    struct list *p2 = ls->next;
    struct list *p3;
    struct list *last = ls->next;

    while(p2) {
        p3 = p2->next;
        p2->next = p1;
        p1 = p2;
        p2 = p3;
    }
    last->next = NULL;
    ls->next = p1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值