【C语言数据结构】(一)单链表

本文详细介绍了如何使用C语言创建单链表的过程。包括定义节点结构、创建新节点及链表函数等内容。通过实例演示了如何逐步构建链表并进行基本操作。

一.建立单链表步骤

  1. 定义结点的数据存储结构
typedef struct node{
    int Element;//结点元素值
    struct node *next;  //后继结点
}Node;
  1. 定义创建新结点函数,该函数为新结点开辟空间并且赋予元素值,最后函数返回创建的该新结点
Node* NewNode(){
    Node* newNode;
    newNode = (Node *) malloc(sizeof(Node));
    printf("请输入该结点的元素值:");
    scanf("%d", &newNode->Element);
    newNode->next = NULL;//让下一个结点为NULL,为什么,因为NULL就是链表的尾巴
    return newNode;
}
  1. 建立链表函数,内包含创建新结点函数Node*NewNode(),调用该函数之后将该新结点接入链表头,可以连续创建新结点,并且接入到链表当中,最后函数返回整个链表的头结点。有了这个头结点我们就可以进行增删改查等基础操作了。
Node* BuildList(Node* first) {
    Node* p,*head;      //定义结点p是我们用来创建新结点,定义结点head用来存放first的地址,直接用first不太合适
    char c; //用于程序控制
	head = first;  
	printf("输入y开始建立:");
    while((c = getchar()) != 'n'){
        p = NewNode();  //建立一个新的结点
        if(first == NULL){
            head = p;  //head接收了创建了第一个结点,那么就是拥有了整条链表
			first = head;//把头固定好:frist存放第一个结点的值,那么无论head被偏移到任何结点,first存放的地址始终是头结点的地址
        }
        else{
            head->next = p;
            head = head->next;//让这条链表从头结点开始往后滑
        }
        printf("Another element?y/n\n");
		getchar();//吸收回车符
    }
	
    return first;
}

二.完整代码

#define Maxsize 50
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
    int Element;//结点元素值
    struct node *next;  //后继结点
}Node;
//建立新结点函数(为结点开辟空间,赋予结点元素值)
Node* NewNode(){
    Node* newNode;
    newNode = (Node *) malloc(sizeof(Node));
    printf("请输入该结点的元素值:");
    scanf("%d", &newNode->Element);
    newNode->next = NULL;//让下一个结点为NULL,为什么,因为NULL就是链表的尾巴
    return newNode;
}

//建立单链表函数,以一个空结点作为形参
Node* BuildList(Node* first) {
    Node* p,*head;      //定义结点p是我们用来创建新结点,定义结点head用来存放first的地址,直接用first不太合适
    char c; //用于程序控制
	head = first;  
	printf("输入y开始建立:");
    while((c = getchar()) != 'n'){
        p = NewNode();  //建立一个新的结点
        if(first == NULL){
            head = p;  //head接收了创建了第一个结点,那么就是拥有了整条链表
			first = head;//把头固定好:frist存放第一个结点的值,那么无论head被偏移到任何结点,first存放的地址始终是头结点的地址
        }
        else{
            head->next = p;
            head = head->next;//让这条链表从头结点开始往后滑
        }
        printf("Another element?y/n\n");
		getchar();//吸收回车符
    }
	
    return first;
}

//打印创建的链表
void printLink(Node *first){
    printf("链表的元素有这些:");
    while(first){
        printf("%d ", first->Element);
        first = first->next;   //链表的遍历
    }
}
void main()
{
    Node *first = NULL;
    first = BuildList(first);
    printLink(first);

}
二.内核链表 内核链表链表,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语言下的单链表,可以增加,删除,查找,销毁节点。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值