链表与内存--头节点和链表分割

简介: 链表与内存--头节点和链表分割

上篇写到了链表,后来发现自己对链表的理解还有些偏差,重新做了下链表测试,优化了相关代码。
主要改动的地方是:之前理解的链表为一个节点一个节点串联起来,后来查看资料,发现如果给链表增加一个空节点,使用起来会更加方便。也就是说,链表表头的第一个节点只有地址,没有实际数据,当然我们也可以给他填充上一些数据比如链表长度等。从第二个节点开始节点有了地址和数据,我们称第二个节点为头指针。很显然,头节点不一定是头指针,头节点可以没有,但头指针必须有。
[头节点] -> [头指针]->[ ] -> NULL
那么加入头节点之后,代码瞬间就变得统一起来,而且也更加好理解。
如增加一个节点到链表,可以如下定义,可对比之前的文章中的添加节点代码。
下面是增加头节点后的代码,敬请参考。

增加元素到链表

/* 增加一个元素到链表中 
*     head -- 链表头节点
*     item -- 要增加的加点
*    Opr  -- 0(增加到头指针) -1(增加到尾指针) >0 增加到对应节点之后
*/
U8 NodeAdd(struct node **head, struct node *item, S8 Oper)
{
    struct node *temp;
        
    /* 头节点为空,链表未分配地址 */
    if (*head == NULL)
    {
        return 0;
    }

    /* 添加到头指针 */
    if (Oper == 0)
    {
        item->next = (*head)->next;
        (*head)->next = item;
        (*head)->data++;
        return 1;
    }
    else if (Oper == -1) /* 添加到尾指针 */
    {
        temp = (*head)->next; /* 获取链表头指针 */
            while(temp)
        {
            if (temp->next == NULL)
            {
                item->next = *head;
                //item->next = NULL;         /* 先续尾 */
                temp->next = item;        /* 再接头 */
                (*head)->data++;
                return 1;
            }
            temp = temp->next;
        }
    }
    else
    {
        temp = (*head)->next; /* 获取链表头指针 */
        while(temp)
        {
            if (temp->index == Oper)
            {
                item->next = temp->next;     /* 先续尾 */
                temp->next = item;            /* 再接头 */
                (*head)->data++;
                return 1;
            }
            temp = temp->next;
        }
    }
    return 2;//节点索引错误
}

删除链表中节点

/* 在链表中删除指定节点 */
U8 NodeDel(struct node **head, U8 DelIndex)
{
    struct node *nodeforward; /* 查询节点指针 */
    struct node *nodetemp;        /* 暂存节点指针 */

    /* 头节点空 */
    if (*head == NULL)
    {
        return 0;
    }

    nodeforward = (*head); /* 查询指针指向头节点 */

    while(nodeforward->next)
    {
        nodetemp = nodeforward; 
        nodeforward = nodeforward->next;

        if (nodeforward->index == DelIndex)
        {
            nodetemp->next = nodeforward->next;
            (*head)->data--;
            return 1;
        }
    }
    return 2;
}

修改指定节点的值


//修改指定节点中的值
U8 NodeModifyIndex(struct node **head, U8 *data,U8 modifyindex)
{
    struct node *temp;

    if (*head == NULL)
    {
        return 0;
    }

    temp = *head;

    while(temp)
    {
        if (temp->index == modifyindex)//找到指定节点
        {
            memcpy(&temp->data,data,sizeof(temp->data));
            return 1;
        }
        temp = temp->next;
    }
    return 2;//没有找到对应节点
}

将一个链表按顺序分割

/*
*     将一个链表按照给定值val排序,大于等于val的放在后面,小于val的放在前面
*    链表带头结点: [头结点] -> [头指针] -> [] -> []
*    头结点存放结点个数,索引为0
*/
U8 NodeCut2Parts(struct node **head,U8 val)
{
    struct node *temp = NULL;
    struct node *small = NULL;
    struct node *big = NULL;
    struct node *ptrsmall = NULL; /* 指向small链表各结点的指针 */
    struct node *ptrbig = NULL;    

    small = (struct node *)malloc(sizeof(struct node));
    big = (struct node *)malloc(sizeof(struct node));

    ptrsmall = small;
    ptrbig = big;

    if (*head == NULL)/* 链表为空,头节点 */
    {
        free(small);
        free(big);
        return 0;
    }
    else
    {
        temp = (*head)->next;/* 头指针赋值 */
        
        while(temp)
        {
            if (temp->index < val)
            {
                ptrsmall->next = temp;
                ptrsmall = ptrsmall->next; /* small链表节点指针后移 */
            }
            else
            {
                ptrbig->next = temp;
                ptrbig = ptrbig->next;    /* big链表节点指针后移 */
            }
            temp = temp->next; /* 原链表节点指针后移 */
        }
        /* 将大小链表的最后节点指向NULL */
        ptrsmall->next = NULL; 
        ptrbig->next = NULL;

        ptrsmall->next = big->next; /* 大小链表合并 */
        (*head)->next = small->next;/* 合并后赋值给原链表 */
        free(small);
        free(big);
    }
}
主程序可以用来测试功能
void main()
{
    U8 datamodify = 0xAB;
    struct node *NewNodeList;
    struct node Node[10];


    NewNodeList->data = 0;
    NewNodeList->index = 0;
    NewNodeList->next = NULL;

    /* 给10个节点赋值 */
    for (i=0;i<10;i++)
    {
        Node[i].index = i+1;
        Node[i].data = (U8)(((i+1)&0x0F)|(((i+1)<<4)&0xF0));
        Node[i].next = NULL;
    }

    //1. 分别把Node1,2,3 加入链表
    NodeAdd(&NewNodeList,&Node[0],0);
    NodeAdd(&NewNodeList,&Node[5],0);
    NodeAdd(&NewNodeList,&Node[3],0);
    NodeAdd(&NewNodeList,&Node[8],0);
    NodeAdd(&NewNodeList,&Node[1],-1);

    //GetNodeNum(&NewNodeList);
    
    NodeAdd(&NewNodeList,&Node[6],-1);
    NodeAdd(&NewNodeList,&Node[2],-1);
    NodeAdd(&NewNodeList,&Node[7],-1);
    NodeAdd(&NewNodeList,&Node[4],6);
    NodeAdd(&NewNodeList,&Node[9],1);

    //4. 删除指定节点
    NodeDel(&NewNodeList,2);

    //5. 修改某个节点的值
    NodeModifyIndex(&NewNodeList,&datamodify,1);

    NodeCut2Parts(&NewNodeList,5);
}
相关文章
|
3月前
LeetCode第二十四题(两两交换链表中的节点)
这篇文章介绍了LeetCode第24题的解法,即如何通过使用三个指针(preNode, curNode, curNextNode)来两两交换链表中的节点,并提供了详细的代码实现。
30 0
LeetCode第二十四题(两两交换链表中的节点)
|
3月前
Leetcode第十九题(删除链表的倒数第N个节点)
LeetCode第19题要求删除链表的倒数第N个节点,可以通过快慢指针法在一次遍历中实现。
48 0
Leetcode第十九题(删除链表的倒数第N个节点)
05_删除链表的倒数第N个节点
05_删除链表的倒数第N个节点
|
3月前
(剑指offer)18、删除链表的节点—22、链表中倒数第K个节点—25、合并两个排序的链表—52、两个链表的第一个公共节点(2021.12.07)
(剑指offer)18、删除链表的节点—22、链表中倒数第K个节点—25、合并两个排序的链表—52、两个链表的第一个公共节点(2021.12.07)
57 0
|
3月前
【数据结构】环形、相交、回文、分割、合并、反转链表
【数据结构】环形、相交、回文、分割、合并、反转链表
32 0
|
5月前
|
算法
LeetCode第24题两两交换链表中的节点
这篇文章介绍了LeetCode第24题"两两交换链表中的节点"的解题方法,通过使用虚拟节点和前驱节点技巧,实现了链表中相邻节点的交换。
LeetCode第24题两两交换链表中的节点
04_两两交换链表中的节点
04_两两交换链表中的节点
|
4月前
|
Prometheus Kubernetes 监控
使用kubectl快速查看各个节点的CPU和内存占用量
在Kubernetes集群中,安装metrics-server,并使用kubectl快速查看集群中各个节点的资源使用情况。
311 0
|
5月前
|
Python
【Leetcode刷题Python】剑指 Offer 22. 链表中倒数第k个节点
Leetcode题目"剑指 Offer 22. 链表中倒数第k个节点"的Python解决方案,使用双指针法找到并返回链表中倒数第k个节点。
59 5
|
5月前
|
Python
【Leetcode刷题Python】剑指 Offer 18. 删除链表的节点
Leetcode题目"剑指 Offer 18. 删除链表的节点"的Python解决方案,通过使用双指针法找到并删除链表中值为特定数值的节点,然后返回更新后的链表头节点。
47 4

热门文章

最新文章