C语言实现 单链表和双链表 处理基本类型数据

引言:C语言链表在开发过程十分重要,以下为详细的实现过程,包括单向链表、双向链表,含头节点链表,不含头节点链表。

1 单向链表实现(有表头,表头未存储数据)

1.1 单项链表构造

typedef struct Node //单链表定义
{
    int data;//先以基本数据类型为例,后再分析复杂数据类型
    struct Node *next;
} Node;

1.2 创建单链表表头,此表头不含有效数据

Node *headNode() //单链表创建表头(不存储有效数据)
{
    Node *node = (Node *)malloc(sizeof(Node)); //向堆区申请内存
    node->data = 0;
    node->next = NULL; // next指向下一个节点,node指向的是当前节点
    return node;       //返回头节点
}

1.3 根据数据创建节点

Node *createSingleNode(int data) //单链表创建节点
{
    Node *node = (Node *)malloc(sizeof(Node));
    node->data = data;
    node->next = NULL;
    return node;
}

1.4-1 头插插入节点,即新插入的节点链接在head后面

Node *insertSingleNodeByHead(int data, Node *headNode) //单链表有表头头插法
{
    Node *node = createSingleNode(data);
    node->next = headNode->next;
    headNode->next = node;
    return node;
}

1.4-2 尾插插入节点,即新插入的节点链接在最后一个节点之后

Node *insertSingleNodeByTail(int data, Node *headNode) //单链表尾插法
{
    Node *node = createSingleNode(data);
    Node *pointer = headNode;
    while (pointer->next)
        pointer = pointer->next;
    pointer->next = node;
    node->next = NULL;
    return node;
}

1.5 删除data对应的首个节点

int deleteSingleNode(int deleteData, Node *headNode) //单链表删除节点
{
    Node *pointer = headNode;
    while (pointer->next)
    {
        if (pointer->next->data == deleteData)
        {
            Node *deleteNode = pointer->next;
            pointer->next = pointer->next->next;
            free(deleteNode);//释放删除节点占用的堆内存
            return 1;
        }
        pointer = pointer->next;
    }
    return 0;//删除失败返回0
}

1.6 单链表遍历

void printfList(void *list)//为方便函数回调,写此函数方便提供程序的可扩展性
{
    Node *node = (void *)list;
    printf("%d->\t", node->data);
}
void listNode(Node *headNode, int withEmptyHeadNode, void (*printfList)(void *)) //节点遍历
{
    Node *pointer = (withEmptyHeadNode == 1 ? headNode->next : headNode);//头节点data是否有效,无效为1
    while (pointer)
    {
        printfList(pointer);
        pointer = pointer->next;
    }
    puts("\n");
}

1.7 代码运行

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int arr[] = {1, 2, 3, 4, 5, 6};
    Node *head = headNode();//头节点创建
    for (int i = 0; i < 3; i++)
        insertSingleNodeByHead(arr[i], head);//头插节点
    listNode(head, 1, printfList);
    for (int i = 3; i < 6; i++)
        insertSingleNodeByTail(arr[i], head);//尾插节点
    listNode(head, 1, printfList);
    for (int i = 2; i < 4; i++)
        deleteSingleNode(arr[i], head);//删除节点
    listNode(head, 1, printfList);//遍历节点
    return 0;
}

结果如下:

2 单向链表实现(未创建不含数据的表头,首节点直接存储了数据)

2.1 单项链表的构造,与节点创建,及尾插节点,和含空数据标头的链表创建一致,代码如下

typedef struct Node//结构体构造单链表
{ 
    int data;
    struct Node *next;
} Node;
Node *createSingleNode(int data)//创建data的单链表节点
{
    Node *node = (Node *)malloc(sizeof(Node));
    node->data = data;
    node->next = NULL;
    return node;
}
void insertSingleNodeByTail(int data, Node *firstNode)//尾插节点,因为首地址不变,传一级指针即可
{
    Node *node = createSingleNode(data);
    Node *pointer = firstNode;
    while (pointer->next)
        pointer = pointer->next;
    pointer->next = node;
    node->next = NULL;
}

2.2 头插节点,由于头插导致链表首节点地址在不断变化,即Node *head变化,需要传一级指针的地址Node **firstNode作为入参

void insertSingleNodeByHead(int data, Node **firstNode)
{
    Node *node = createSingleNode(data);
    node->next = *firstNode;
    *firstNode = node;
}

2.3 节点删除,考虑到首节点可能被删除,入参需为二级指针

int deleteSingleNode(int data, Node **firstNode)//首节点存在删除可能,因此需要传址
{
    if (firstNode == NULL)
        return 0;
    if ((*firstNode)->data == data)
    {
        Node *deleteNode = *firstNode;
        *firstNode = (*firstNode)->next;
        free(deleteNode);
        return 1;
    }
    Node *pointer = *firstNode;
    while (pointer->next)
    {
        if (pointer->next->data == data)
        {
            Node *deleteNode = pointer->next;//pointer->next为需要删除的节点
            pointer->next = pointer->next->next;
            free(deleteNode);
            return 1;
        }
        pointer = pointer->next;
    }
    return 0;
}

2.4 链表遍历代码实现和含空数据头节点链表一致

#include <stdio.h>
#include <stdlib.h>
void printfList(void *list) //为方便函数回调,写此函数方便提供程序的可扩展性
{
    Node *node = (void *)list;
    printf("%d->\t", node->data);
}
void listNode(Node *headNode, int withEmptyHeadNode, void (*printfList)(void *)) //节点遍历
{
    Node *pointer = (withEmptyHeadNode == 1 ? headNode->next : headNode); //头节点data是否有效,无效为1
    while (pointer)
    {
        printfList(pointer);
        pointer = pointer->next;
    }
    puts("\n");
}


int main()
{
    int arr[] = {1, 2, 3, 4, 5, 6};
    Node *firstNode = createSingleNode(arr[0]);//创建含有效数据的首节点
    for (int i = 1; i < 4;i++)
        insertSingleNodeByHead(arr[i], &firstNode);//头插
    listNode(firstNode, 0, printfList);//遍历
    for (int i = 4; i < 6;i++)
        insertSingleNodeByTail(arr[i], firstNode);//尾插
    listNode(firstNode, 0, printfList);
    for (int i = 4; i < 6;i++)
        deleteSingleNode(arr[i], &firstNode);//删除后两个节点
    listNode(firstNode, 0, printfList);
    for (int i = 2; i < 4;i++)
        deleteSingleNode(arr[i], &firstNode);//删除前两个节点(arr[2]和arr[3])
    listNode(firstNode, 0, printfList);
    return 0;
}

结果如下

 3 双向链表实现(有表头,表头未存储数据)

3.1 双向链表构造

typedef struct Node
{
    int data;
    struct Node *pre;  //前驱节点
    struct Node *next; //后继节点
} Node;

3.2 创建双向链表表头

Node *headNode()
{
    Node *node = (Node *)malloc(sizeof(Node));
    node->next = node; //头节点的前后指向均为自身
    node->pre = node;
    node->data = 0; //仅为初始化,非有效数据
    return node;
}

3.3 根据data创建节点

Node *createSingleNode(int data)
{
    Node *node = (Node *)malloc(sizeof(Node));
    node->data = data;
    node->next = NULL;
    node->pre = NULL;
    return node;
}

3.4 向双向链表插入节点,分为头插和尾插


void insertSingleNodeByTail(int data, Node *head)//尾插节点
{
    Node *node = createSingleNode(data);
    Node *pointer = head;
    while (pointer.next != head) //最后一个节点next指向head
        pointer = pointer->next;
    node->next = head; // node作为尾节点,next指向head
    head.pre = node;
    pointer.next = node; // pointer为原链表最后一个节点,next应指向新节点
    node.pre = pointer;
}
void insertSingleNodeByHead(int data, Node *head)//头插节点
{
    Node *node = createSingleNode(data);
    Node *headPointer = head;
    node.pre = headPointer;
    node->next = headPointer.next;//新节点next指向原head后的首个节点
    headPointer->next->pre = node;
    headPointer->next = node;//头节点next指向新节点
    
}

3.5 删除data对应的首个节点

int deleteSingleNode(int data, Node *head)
{
    Node *pointer = head.next;
    while (pointer!= head)
    {
        if (pointer->data == data)//pointer即为需要删除的节点
        {
            pointer.pre.next = pointer.next;
            pointer.next.pre = pointer.pre;
            free(pointer);//释放pointer占用的堆内存
            return 1;
        }
        pointer = pointer.next;
    }
    return 0;//删除失败返回0
}

双向链表的实现比较简单,不再写主函数。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jakerc

原创不易,您的奖励将是我最大的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值