[数据结构和算法]C语言实现简单的双向循环链表

其实链表很简单,跟着我的脚步走,基本是这篇博客看完,你也就能实现简单的链表操作了

数组、链表是最常见的重要的数据结构,所以掌握链表也是很重要的咯。
一般链表的操作无外乎增删改查。 今天就简单的实现一下双向循环链表的增删

1. 链表的数据结构,主要包含指针域和数据域

双向循环链表的数据结构包含至少两个指针和至少一个数据
在这里插入图片描述

//用结构体封装一下链表的数据结构
typedef struct _node_t{
    struct _node_t *prev;	//上一个节点
    struct _node_t *next;	//下一个节点
    uint8_t data;				//数据域
}Node,*pNode;
2.链表的初始化,即创建一个头结点

头结点的prev或next都是其本身,一般建议头节点只存指针。
在这里插入图片描述

//链表初始化,即创建一个头结点
pNode linklist_init(void){
    pNode head = (pNode)malloc(sizeof(Node));	//申请内存
    if(NULL == head){
        perror("malloc Node failed!");
    }
    head->prev = head;	//头节点的prev指向本身
    head->next = head; //头节点的next指向本身
    return head;
}
3.链表的插入

在前面插入,即在头结点之后插入:
来来来,排队了,,新来了一个童鞋tmp,个子比较矮的,老师让他站在排头的后面;
新来的tmp看了一下前面是排头(head),后面是某某(head->next),然后他记住了自己的位置,通过自己前面和后面的童鞋定位了自己的位置;
可是还不够啊,排头和之前在排头后面的童鞋不知道啊,所以之前排头后面的童鞋,重新定位了一下自己的位置(head->next->prev)我原来在排头后面,但是现在我前面是谁?排头后面的换了,排头也定位了一下自己的位置(head->next) 我后面新来的是谁呀。
在这里插入图片描述

pNode linklist_addhead(pNode head, uint8_t dat){
    pNode tmp = (pNode)malloc(sizeof(Node));	//申请内存
    if(tmp == head){
        perror("malloc Node failed!");
    }
    tmp->prev = head;	//tmp定位自己,看下前面是谁
    tmp->next = head->next;	//再看看后面是谁
    head->next->prev = tmp;	//原来在排头后面的童鞋,看看现在自己前面的是谁
    head->next = tmp;	//排头也看了下,现在自己后面的是谁
    tmp->data = dat;	//新来的童鞋的名字
    return head;	//排头的位置不能丢,不然找不到这一队人马了
}

在末尾插入
这里就不再赘述了,直接上图,看不懂的,看上图及描述
在这里插入图片描述

pNode linklist_addtail(pNode head, uint8_t dat){
    pNode tmp = (pNode)malloc(sizeof(Node));
    if(tmp == head){
        perror("malloc Node failed!");
    }
    tmp->prev = head->prev;	//tmp看下自己前面是谁,主要前面是排头ing,因为是环形的链表
    tmp->next = head;	//tmp看下自己后面的是谁
    head->prev->next = tmp;	//原来排头前面的童鞋的后面是谁,来新人tmp了
    head->prev = tmp;	//现在排头前面的换成了tmp了
    tmp->data = dat;
    return head;
}

还有其他插入方法,但是只要掌握了头插尾插,其他的都是浮云

3.链表的删除

从头删除,即将排头后面的tmp童鞋删除
先告诉tmp童鞋后面的童鞋(tmp->next),我走了之后你前面的是谁;然后告诉tmp童鞋前面的童鞋(这里head),我走了之后你后面的是谁;把前后两个童鞋定位告诉他们后就可以离开了(free);
在这里插入图片描述

pNode Linklist_delhead(pNode head){
    pNode tmp = head->next; 
    if(tmp == head){
        perror("linklist empty!");
        return head;
    }
    tmp->next->prev = head;	//tmp走了,tmp童鞋后面的童鞋的前面变成了排头
    head->next = tmp->next;	//tmp走了,排头后面的童鞋变成了原来排在tmp童鞋后面的童鞋
    tmp->next = NULL;
    tmp->prev = NULL;
    free(tmp);	//释放内存
}

从尾部删除
这里就不再赘述了,直接上图,看不懂的,看上图及描述
在这里插入图片描述

pNode Linklist_deltail(pNode head){
    pNode tmp = head->prev;
    if(tmp == head){
        perror("linklist empty!");
        return head;
    }
    tmp->prev->next = head;
    head->prev = tmp->prev;
    tmp->next = NULL;
    tmp->prev = NULL;
    free(tmp);
}
4. 遍历显示链表

从排头依次报数,轮流一圈,回到排头就完成了

void linklist_show(pNode head){
    tmp = head->next;	//从排头后面的童鞋开始遍历
    while(tmp != head){	//没有遍历到排头
        printf("%p:%d\n",tmp, tmp->data);
        tmp = tmp->next;	//指向下一个童鞋
    }
}
5. 测试
int main(void){
    pNode head = linklist_init();
    printf("\nhead add Node!\n");
    for(uint8_t i=0;i<5;i++){
        linklist_addhead(head, i);
    }
    linklist_show(head);

    printf("\nhead del!\n");
    for(uint8_t i=0;i<2;i++){
        Linklist_delhead(head);
    }
    linklist_show(head);

    printf("\ntail_del!\n");
    for(uint8_t i=0;i<2;i++){
        Linklist_deltail(head);
    }
    linklist_show(head);

    printf("\ntail add Node!\n");
    for(uint8_t i=0;i<5;i++){
        linklist_addtail(head, i);
    }
    linklist_show(head);

    printf("\ntail del Node!\n");
    Linklist_deltail(head);
    linklist_show(head);

    printf("\nhead del Node!\n");
    Linklist_delhead(head);
    linklist_show(head);    
    return 0;
}

运行结果
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章