双向链表(c语言)

什么是链表?链表的分类?

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

链表应该在学习数据结构中最简单的一种了吧,其实在linux内核中链表也随处可见,今天就来重新温习一下链表,该文以双向链表结构讲解。

链表分类

其实链表有好多种,对于初学者来说,被搞的乱七八糟。下面以图解的方式呈现给大家:

​ 

 

看上面的图 2 × 2 × 2 可以得到8种链表,比如非循环带头单向链表就是最简单的,也是学数据结构最开始学习的链表结构。

双向链表

那么双向带头链表,其实对于单链表来说,最大的区别就是在当前链表某个节点,不仅仅知道下一个节点,也知道它的上一个节点

结构

 

typedef struct Node{
    struct Node *prev;
    int elements;
    struct Node *next;
}T_Node,*P_Node;

上面定义了该链表的结构体

创建头结点

首先创建双向链表的头结点

P_Node Create_Head(void)
{
    P_Node head = NULL;
    head = malloc(sizeof(struct Node));
    head->next = NULL;
    head->prev = NULL;
    return head;
}

插入节点元素

插入节点有好多种方式,可以在头部插入,也可以在尾部,同时也可以在尾部插入,在此仅进行尾部插入。

下图是在中间插入元素节点图像:

 

/*
 * 在尾部节点插入新元素,也可以改为头部节点,或者某个位置插入,在此仅仅实现尾部插入新元素
 */
int Insert_Element(P_Node head,int element)
{
    if(!head)
    {
        printf("Head NULL\n");
        return (-1);
    }
    P_Node pTemp = head;
    while(pTemp->next)
        pTemp = pTemp->next;
    P_Node pElement = malloc(sizeof(struct Node));
    pElement->elements = element;
    pTemp->next = pElement;
    pElement->prev = pTemp;
    printf("Insert_Element success : %d\n",element);
    return (0);
}

删除链表节点

写了两个函数一个是删除链表所有节点,包括头结点,另一个是找到某个节点元素,删除这个元素。

/*
 * 删除全部节点
 */
int Delete_List(P_Node head)
{
    if(!head)
    {
        printf("Head NULL\n");
        return (-1);
    }
    P_Node pTemp = head;
    while(pTemp->next)
    {
        pTemp = pTemp->next;
    }

    while(pTemp != NULL)
    {
        free(pTemp);
        pTemp = pTemp->prev;
    }
    return (0);
}
/*
 * 删除某个节点
 */
int Delete_element(P_Node head,int element){
    P_Node pTmp = head->next;
    while(pTmp){
        if(pTmp->elements == element){
            if(!pTmp->prev){//如果是第一个元素
                head->next = pTmp->next;
                pTmp->next = NULL;
                free(pTmp);
                return (0);
            } else if(!pTmp->next){//如果是最后一个元素
                pTmp->prev->next = NULL;
                free(pTmp);
                return (0);
            }else{
                pTmp->prev->next = pTmp->next;
                pTmp->next->prev = pTmp->prev;
                free(pTmp);
                return (0);
            }
        }
        pTmp = pTmp->next;
    }
    printf("Not Found !\n");
    return (-1);
}

遍历链表元素

遍历链表有好多种方法,在此进提供从头遍历代码参考,遍历链表,其实应该是很简单的操作,一个while循环就可以解决。

int Print_List(P_Node head)
{
    if(!head->next)
    {
        printf("Head NULL\n");
        return (-1);
    }
    P_Node pTemp = head->next;
    printf("list:  ");
    while(pTemp)
    {
        if(!pTemp->next){
            printf("%d\n",pTemp->elements);
        }else{
            printf("%d->",pTemp->elements);
        }
        pTemp = pTemp->next;
    }

    return (0);
}

查找链表元素

查找与遍历类似,只不过在遍历的基础上查找元素是否匹配。

int Find_List(P_Node head,int element)
{
    P_Node pTmp = head->next;
    int i=1;
    while (pTmp)
    {
        if (pTmp->elements == element)
        {
            printf("find %d in %d \n",element,i);
            return i;
        }
        i++;
        pTmp=pTmp->next;
    }
    printf("Not Found !\n");
    return (-1);
}

完整代码

#include "stdio.h"
#include "stdlib.h"

typedef struct Node{
    struct Node *prev;
    int elements;
    struct Node *next;
}T_Node,*P_Node;

P_Node Create_Head(void)
{
    P_Node head = NULL;
    head = malloc(sizeof(struct Node));
    head->next = NULL;
    head->prev = NULL;
    return head;
}
/*
 * 在尾部节点插入新元素,也可以改为头部节点,或者某个位置插入,在此仅仅实现尾部插入新元素
 */
int Insert_Element(P_Node head,int element)
{
    if(!head)
    {
        printf("Head NULL\n");
        return (-1);
    }
    P_Node pTemp = head;
    while(pTemp->next)
        pTemp = pTemp->next;
    P_Node pElement = malloc(sizeof(struct Node));
    pElement->elements = element;
    pTemp->next = pElement;
    pElement->prev = pTemp;
    printf("Insert_Element success : %d\n",element);
    return (0);
}
/*
 * 遍历链表
 */
int Print_List(P_Node head)
{
    if(!head->next)
    {
        printf("Head NULL\n");
        return (-1);
    }
    P_Node pTemp = head->next;
    printf("list:  ");
    while(pTemp)
    {
        if(!pTemp->next){
            printf("%d\n",pTemp->elements);
        }else{
            printf("%d->",pTemp->elements);
        }
        pTemp = pTemp->next;
    }

    return (0);
}
/*
 * 删除全部节点
 */
int Delete_List(P_Node head)
{
    if(!head)
    {
        printf("Head NULL\n");
        return (-1);
    }
    P_Node pTemp = head;
    while(pTemp->next)
    {
        pTemp = pTemp->next;
    }

    while(pTemp != NULL)
    {
        free(pTemp);
        pTemp = pTemp->prev;
    }
    return (0);
}
/*
 * 删除某个节点
 */
int Delete_element(P_Node head,int element){
    P_Node pTmp = head->next;
    while(pTmp){
        if(pTmp->elements == element){
            if(!pTmp->prev){//如果是第一个元素
                head->next = pTmp->next;
                pTmp->next = NULL;
                free(pTmp);
                return (0);
            } else if(!pTmp->next){//如果是最后一个元素
                pTmp->prev->next = NULL;
                free(pTmp);
                return (0);
            }else{
                pTmp->prev->next = pTmp->next;
                pTmp->next->prev = pTmp->prev;
                free(pTmp);
                return (0);
            }
        }
        pTmp = pTmp->next;
    }
    printf("Not Found !\n");
    return (-1);
}
/*
 * 查找
 */
int Find_List(P_Node head,int element)
{
    P_Node pTmp = head->next;
    int i=1;
    while (pTmp)
    {
        if (pTmp->elements == element)
        {
            printf("find %d in %d \n",element,i);
            return i;
        }
        i++;
        pTmp=pTmp->next;
    }
    printf("Not Found !\n");
    return (-1);
}

int main(int argc,char* argv[]){
    P_Node p_head = Create_Head();
    Insert_Element(p_head,1);
    Insert_Element(p_head,2);
    Insert_Element(p_head,3);
    Insert_Element(p_head,4);
    Insert_Element(p_head,5);
    Insert_Element(p_head,6);
    Print_List(p_head);
    Delete_element(p_head,4);
    Print_List(p_head);
    Find_List(p_head,5);
    Delete_List(p_head);
    return 0;
}

小结

代码很简单,手撸双向链表,链表的知识应该是数据结构中最基础的,学习内核知识,链表也是绕不开的弯,如果从事嵌入式行业,这更是基础,会一直与指针打交道,下次有时间手撸一个栈,今天的内容就分享到这了。

以上代码已测试,如有错误欢迎指正。

大家的点赞在看就是我继续创作的动力,如果觉得写的不错,欢迎关注,点赞,收藏,转发,感谢老铁!

该文章首先发布于下面公众号

欢迎关注 #公众号:技术乱舞 一起交流

灵魂碰撞

### 双向链表的 C 语言实现示例 双向链表是一种链式数据结构,其中每个节点包含数据、指向下一个节点的指针和指向前一个节点的指针。这使得双向链表在插入和删除操作时更加灵活。 #### 数据结构定义 双向链表的节点通常定义如下: ```c typedef struct _Node { int data; // 节点数据 struct _Node* next; // 指向下一个节点 struct _Node* prev; // 指向前一个节点 } Node; typedef Node* Link; ``` #### 初始化双向链表 创建一个空的双向链表通常包括创建一个头节点,该节点不存储实际数据,仅用于标识链表的起始位置: ```c Node* InitList() { Node* head = (Node*)malloc(sizeof(Node)); if (head == NULL) { printf("内存分配失败\n"); exit(1); } head->next = NULL; head->prev = NULL; return head; } ``` #### 插入节点 插入节点到双向链表中需要处理前后指针的关系。例如,在链表的第一个位置插入节点: ```c Node* MakeNode(int data) { Node* newNode = (Node*)malloc(sizeof(Node)); if (newNode == NULL) { printf("内存分配失败\n"); exit(1); } newNode->data = data; newNode->next = NULL; newNode->prev = NULL; return newNode; } Node* InsFirst(Node* head, Node* newNode) { if (head == NULL || newNode == NULL) { return NULL; } newNode->next = head->next; if (head->next != NULL) { head->next->prev = newNode; } head->next = newNode; newNode->prev = head; return newNode; } ``` #### 遍历链表 遍历链表可以通过一个函数实现,该函数接受链表头节点和一个打印函数作为参数: ```c void ListTraverse(Node* head, void (*print)(int)) { Node* current = head->next; while (current != NULL) { print(current->data); current = current->next; } } ``` #### 删除节点 删除链表的第一个节点需要更新头节点和下一个节点的指针: ```c void FreeNode(Node* node) { if (node != NULL) { free(node); } } Node* DelFirst(Node* head) { if (head == NULL || head->next == NULL) { return NULL; } Node* firstNode = head->next; head->next = firstNode->next; if (firstNode->next != NULL) { firstNode->next->prev = head; } return firstNode; } ``` #### 销毁链表 销毁整个链表可以释放所有节点占用的内存: ```c void DestroyList(Node* head) { Node* current = head; while (current != NULL) { Node* nextNode = current->next; free(current); current = nextNode; } } ``` #### 完整示例 以下是一个完整的双向链表示例: ```c #include <stdio.h> #include <stdlib.h> typedef struct _Node { int data; struct _Node* next; struct _Node* prev; } Node; Node* InitList() { Node* head = (Node*)malloc(sizeof(Node)); if (head == NULL) { printf("内存分配失败\n"); exit(1); } head->next = NULL; head->prev = NULL; return head; } Node* MakeNode(int data) { Node* newNode = (Node*)malloc(sizeof(Node)); if (newNode == NULL) { printf("内存分配失败\n"); exit(1); } newNode->data = data; newNode->next = NULL; newNode->prev = NULL; return newNode; } Node* InsFirst(Node* head, Node* newNode) { if (head == NULL || newNode == NULL) { return NULL; } newNode->next = head->next; if (head->next != NULL) { head->next->prev = newNode; } head->next = newNode; newNode->prev = head; return newNode; } void ListTraverse(Node* head, void (*print)(int)) { Node* current = head->next; while (current != NULL) { print(current->data); current = current->next; } } void FreeNode(Node* node) { if (node != NULL) { free(node); } } Node* DelFirst(Node* head) { if (head == NULL || head->next == NULL) { return NULL; } Node* firstNode = head->next; head->next = firstNode->next; if (firstNode->next != NULL) { firstNode->next->prev = head; } return firstNode; } void DestroyList(Node* head) { Node* current = head; while (current != NULL) { Node* nextNode = current->next; free(current); current = nextNode; } } void print(int data) { printf("数据项为%d\n", data); } int main() { Node* plist = InitList(); Node* p = InsFirst(plist, MakeNode(1)); InsFirst(plist, MakeNode(2)); InsFirst(plist, MakeNode(3)); printf("遍历输出各节点数据项:\n"); ListTraverse(plist, print); printf("除了头节点该链表共有%d个节点\n", 2); // 假设链表中有两个节点 FreeNode(DelFirst(plist)); printf("删除第一个节点后重新遍历输出为:\n"); ListTraverse(plist, print); printf("除了头节点该链表共有%d个节点\n", 1); // 假设链表中有一个节点 DestroyList(plist); printf("链表已被销毁\n"); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

艾恩凝

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值