c语言单链表

5.单链表

单链表是一种链式的线性结构

链式结构中每个存储数据的结构称之为节点

单链表来说任何节点只能沿着一个方向访问到下一个节点

相邻的节点之间用指针连接(指针保存在节点结构中,指针指向下一个节点)

单链表最后一个节点的指针域必须指向NULL

可以使用头指针或者无效头结点代表一个单链表

其中头指针直接指向单链表中第一个节点,无效头结点的数据域不使用,指针域指向单链表第一个节点

我们可以使用头结点或者头指针代表整个链表

连式结构中节点个事可以根据需要随时调整,不会造成空间浪费

动态分配节点的内存能够根据需要分配合适大小的内存空间

#include <stdio.h>
#include <stdlib.h>
#include “linklist.h”

//创建一个空链表
linklist_t create_emptylist()
{
//创建头节点
linklist_t head = (linklist_t)malloc(sizeof(linklist));
if(head){
head->data = -1;//无效数据
head->next = NULL;//空链表
}

return head;

}

//销毁链表
void clear_list(linklist_t head)
{
linklist_t p = NULL,q = NULL;

q = head->next;
head->next = NULL;

while(q){
    p = q;
    q = q->next;
    free(p);
}
p = NULL;

}

void destory_list(linklist_t *phead)
{
linklist_t head = *phead,p = NULL;

*phead = NULL;

while(head){
    p = head;
    head = head->next;
    free(p);
}
p = NULL;   

}

//按位置查找
linklist_t search_by_pos(linklist_t head,int pos)
{
int i = 1;
head = head->next;

while(head){
    if(i==pos)
        return head;
    head = head->next;
    i++;
}

return NULL;

}

//按位置删除
linklist_t delete_by_pos(linklist_t head,int pos)
{
linklist_t del = NULL,front = NULL;

del = search_by_pos(head,pos);
if(del){
    //找到要删除的前一个节点
    //第一个节点的前一个节点是头节点
    if(pos==1)
        front = head;
    else
        front = search_by_pos(head,pos-1);

    //将前一介节点的指针域指向要删除节点的下一个节点
    front->next = del->next;
    free(del);
    del = NULL;
}

return front; 

}

//从指定位置之后插入,返回插入节点的地址
static linklist_t insert_by_pos(linklist_t p,T dt)
{
//1.构造新节点
linklist_t newnode = (linklist_t)malloc(sizeof(linklist));
if(newnode){
//2.将新节点的指针域指向下一个节点
newnode->next = p->next;
//3.将原位置的指针域指向新节点
p->next = newnode;
newnode->data = dt;
}

return newnode;

}

//从头部插入
linklist_t insert_from_head(linklist_t head,T dt)
{
return insert_by_pos(head,dt);
}

//从尾部插入
linklist_t insert_from_tail(linklist_t head,T dt)
{
linklist_t tail = head;

//找到最后一个节点
while(tail->next)
    tail = tail->next;

return insert_by_pos(tail,dt);

}

void travel(linklist_t head)
{
//略过无效头节点
head = head->next;

while(head){
    printf("%d ",head->data);
    head = head->next;
}
printf("\n");

}

单链表(https://download.csdn.net/download/qq_41256954/11079082)

二.内核链表 内核链表是一种链表,Linux内核中的链表都是用这种形式实现的 1.特性 内核链表是一种双向循环链表,内核链表的节点节点结构中只有指针域 使用内核链表的时候,将内核链表作为一个成员放入到一个结构体中使用 我们在链表中找到内核链表结构的地址,通过这个地址就可以找到外部大结构体的地址,通过大结构体就可以访问其中的成员 优势: 内核链表突破了保存数据的限制,可以用内核链表来保存任何数据(使用一种链表表示各种类型的数据,通用性很强) 内核链表中只有指针域,维护起来更加方便,效率更高 2.使用 内核链表在内核中已经被实现,我们只需要调用其接口直接使用即可 内核链表的实现代码在内核源代码的list.h文件中 3.源代码分析 (1)节点结构: struct list_head { struct list_head *next, *prev;//前置指针 后置指针 }; (2)初始化 #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) (3)插入 //从头部插入 static inline void list_add(struct list_head *new, struct list_head *head)//传入要插入的节点和要插入的链表 { __list_add(new, head, head->next); } //从尾部插入 static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } (4)通过节点找到外部结构体的地址 //返回外部结构体的地址,第一个参数是节点地址,第二个参数是外部结构体的类型名,第三个参数是节点在外部结构体中的成员名 #define list_entry(ptr, type, member) ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) (5)遍历内核链表 //遍历内核链表 #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); \ pos = pos->next) //安全遍历内核链表 #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) 二.内核链表 内核链表是一种链表,Linux内核中的链表都是用这种形式实现的 1.特性 内核链表是一种双向循环链表,内核链表的节点节点结构中只有指针域 使用内核链表的时候,将内核链表作为一个成员放入到一个结构体中使用 我们在链表中找到内核链表结构的地址,通过这个地址就可以找到外部大结构体的地址,通过大结构体就可以访问其中的成员 优势: 内核链表突破了保存数据的限制,可以用内核链表来保存任何数据(使用一种链表表示各种类型的数据,通用性很强) 内核链表中只有指针域,维护起来更加方便,效率更高 2.使用 内核链表在内核中已经被实现,我们只需要调用其接口直接使用即可 内核链表的实现代码在内核源代码的list.h文件中 3.源代码分析 (1)节点结构: struct list_head { struct list_head *next, *prev;//前置指针 后置指针 }; (2)初始化 #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) (3)插入 //从头部插入 static inline void list_add(struct list_head *new, struct list_head *head)//传入要插入的节点和要插入的链表 { __list_add(new, head, head->next); } //从尾部插入 static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } (4)通过节点找到外部结构体的地址 //返回外部结构体的地址,第一个参数是节点地址,第二个参数是外部结构体的类型名,第三个参数是节点在外部结构体中的成员名 #define list_entry(ptr, type, member) ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) (5)遍历内核链表 //遍历内核链表 #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); \ pos = pos->next) //安全遍历内核链表 #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) 二.内核链表 内核链表是一种链表,Linux内核中的链表都是用这种形式实现的 1.特性 内核链表是一种双向循环链表,内核链表的节点节点结构中只有指针域 使用内核链表的时候,将内核链表作为一个成员放入到一个结构体中使用 我们在链表中找到内核链表结构的地址,通过这个地址就可以找到外部大结构体的地址,通过大结构体就可以访问其中的成员 优势: 内核链表突破了保存数据的限制,可以用内核链表来保存任何数据(使用一种链表表示各种类型的数据,通用性很强) 内核链表中只有指针域,维护起来更加方便,效率更高 2.使用 内核链表在内核中已经被实现,我们只需要调用其接口直接使用即可 内核链表的实现代码在内核源代码的list.h文件中 3.源代码分析 (1)节点结构: struct list_head { struct list_head *next, *prev;//前置指针 后置指针 }; (2)初始化 #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) (3)插入 //从头部插入 static inline void list_add(struct list_head *new, struct list_head *head)//传入要插入的节点和要插入的链表 { __list_add(new, head, head->next); } //从尾部插入 static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } (4)通过节点找到外部结构体的地址 //返回外部结构体的地址,第一个参数是节点地址,第二个参数是外部结构体的类型名,第三个参数是节点在外部结构体中的成员名 #define list_entry(ptr, type, member) ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) (5)遍历内核链表 //遍历内核链表 #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); \ pos = pos->next) //安全遍历内核链表 #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) C语言下的单链表,可以增加,删除,查找,销毁节点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值