又见链表

链表

作为一种数据结构,链表以其方便的增删查改功能,实现了无数经典有用的程序。
在之前的帖子里,我构建链表的方式是建立一个不储存数据的head节点,然后通过一边输入数据一边建立结点的方式构建整个链表。
与之前不同的是,这里建立的是包含数据的头结点head:

下面是代码,包含创建部分,输出部分,删除部分,和插入部分。

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

int n = 0; // 结点数 

//=============Node_Creat==============//
Node *Node_Creat()
{
    Node *head = NULL; // 头指针置NULL 

    Node *p1,*p2; // 开辟一个Node大小的空间 使p1和p2指向该空间 
    p1 = p2 = (Node *)malloc(sizeof(Node));
    if(p1 == NULL || p2 == NULL)
    {
        printf("Overflow\n");
        exit(1);
    }

    scanf("%d",&p1 -> data); 

    while(p1 -> data >= 0)
    {
        n++;

        if(head == NULL)
        {
            head = p1;
        } 
        else
        {
            p2 -> next = p1;
        }

        p2 = p1;
        p1 = (Node *)malloc(sizeof(Node));
        if(p1 == NULL)
        {
            printf("Overflow\n");
            exit(1);
        }

        scanf("%d",&p1 -> data);
    }

    p1 = NULL;
    p2 -> next = NULL;
    return head;
}

//============Node_Print==============//
void Node_Print(Node *head)
{
    Node *p = head;
    if(head == NULL) // 链表为空 
    {
        printf("Empty!\n");
        return ;
    }
    else
    {
        printf("Total: %d Node\n",n);
        while(p != NULL)
        {
            printf("%d ",p -> data);
            p = p -> next; 
        }
        printf("\n");
    }
}

//==============Node_Delete()===============//
void Node_Delete(Node *head,int num)
{
    Node *p1,*p2;
    p1 = head;

    if(p1 == NULL) // 链表为空
    {
        printf("Empty\n");
        return ;
    } 

    if(num > n) // 结点不存在 
    {
        printf("Not Found!\n");
        return ;
    }

    n--; // 结点数-1 

    int i;
    for(i = 1; i < num; i++)
    {
        if(p1 -> next == NULL)break;

        p2 = p1;
        p1 = p1 -> next;
    }

    if(p1 == head) // 头节点 即第一个
    {
        head = p1 -> next;
    }
    else
    {
        p2 -> next = p1 -> next;
        free(p1);
    }

    Node_Print(head);
}

//============Node_Insert()============//
void Node_Insert(Node* head,int num,int i_data)
{
    Node * newNode;
    newNode = (Node *)malloc(sizeof(Node));
    if(newNode == NULL)
    {
        printf("Overflow\n");
        exit(1);
    }
    newNode -> data = i_data;
    newNode -> next = NULL;

    Node *p1,*p2;
    p1 = head;

    for(int i = 1 ;i < num; i++)
    {
        p2 = p1;
        p1 = p1 -> next;
    }

    p2 -> next = newNode;
    newNode -> next = p1;

    n++; // 结点数+1 

    Node_Print(head);
}

样例:

链表的反转

我这里采用的方法是 改变两个结点间next指针的指向,原结点next指针指向下一个结点,反转后指向前一个结点。

Node* Node_Reverse(Node* head)
{
    Node* pNow = head;//当前结点
    Node* pPrv = NULL;//当前结点的前一个结点
    Node* pReversedHead = NULL;//反转链表头结点

    Node* pNext = NULL;//当前结点的下一个结点
    while(pNow != NULL)
    {
        pNext = pNow -> next;
        if(pNext == NULL)//如果当前结点的下一个结点为空,那么反转链表的头结点就是当前结点。
        pReversedHead = pNow;

        pNow -> next = pPrv;//当前结点指向前一个结点

        pPrv = pNow;//pPrv和pNow往前移动。
        pNow = pNext;//这里要使用前面保存下来的pNext,不能使用pNow->next
    }
    return pReversedHead;//返回反转链表头指针。
}

大概的一个流程图(反转第一个结点)

注:红色箭头代表pPrev,pNext和pNow的移动,蓝色代表next指针的指向。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值