C语言单链表的创建和简单使用

最近想系统的学习一下数据结构的算法,我的C语言一般,目前还在学习阶段,编写的代码不是很好,如有错误,也是正常,希望大家帮忙指正;

 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。(来自百度)

/*建立一个整数链表*/
/*
1.创建有头结点链表;
2.插入链表
3.删除链表
4.销毁链表
5.打印链表
  */
#include <stdio.h>
#include <stdlib.h> 

typedef int  ElemType;
typedef void ElemTypeVoid;

typedef struct linklist
{
ElemType value;
struct linklist *next;
} Link_List,*LinkList;

//创建链表
LinkList Create_List(ElemType n)
{
LinkList frist;//头结点指针 
LinkList q, p;
ElemType x = 0, i = 0;

frist= (LinkList)malloc (sizeof (Link_List));//头结点分配内存
frist->next = NULL;//头结点指针域清空
q = frist;//将头结点首地址赋值给q

for(i = 1; i < n + 1; ++i)/*输入一个整型的数据*/
{
printf("请输入您的第 %d 数据:",i);
scanf("%d",&x);
p = (LinkList)malloc (sizeof (Link_List));
/*首先为要新创建的表元p开辟一个内存空间*/
if(p == NULL)
{
printf("\n\r Memory allocation failure.\n\r");
return 0;
}
p->value = x;
q->next = p;//将P指向的新结点加入到链表中
q = p;//起着指向下一个结点的作用
}
p->next = NULL;//最后一个结点的指针域清空
printf("\n\r Linked lists are successful!!!\n\r");
return frist;
}

//插入第N个数据
ElemTypeVoid Insert_List(LinkList head)
{
LinkList p, q;
ElemType m, n;


if(head == NULL)
{
printf(" 哪有链表,骗子\n\r");
return;
}
p = head;//将头结点首地址赋值给p
q = (LinkList)malloc(sizeof(Link_List));
if(q == NULL)
{
printf("memory allocated fail\n\r");
return;
}
printf("请输入你想添加的链表号:\n\r");
scanf("%d",&n);
printf("请输入你想添加的链表数据:\n\r");
scanf("%d",&m);
q->value = m;
for(m = 0; m < n - 1; ++m)
{
p = p->next;
}//找到添加的位置
q->next = p->next;//将p->next地址赋给q->next
p->next = q;//相当于p->next = p->next->next
}

//删除第N个数据
ElemTypeVoid Delete_List(LinkList head)
{
LinkList p, q;
ElemType m;
ElemType n;

if(head == NULL)
{
printf("您需要创建一个链表,您骗我乱删数据\n\r");
return;
}
p = head;
printf("请输入你想删除的链表号:\n\r");
scanf("%d",&n);

for(m = 1; m < n; ++m)
{
p = p->next;
}
q = p->next;//将p->next地址赋给q
p->next = q->next;//这块是将q覆盖掉(p->next =p->next->next)
q->next = NULL;//q就是被选定的删除结点
free(q);//删除链表节点第n个
}

//销毁链表
ElemTypeVoid Destroy_List(LinkList head)
{
LinkList p;

if(head == NULL)
{
printf("\n\r 您需要创建一个链表,我不能为你打死他(销毁)。\n\r");
return;
}

while(head)
{
p = head->next;
free(head);
head = p;
}//从头到脚一个一个销毁
printf("\n\r 小弟,已经帮您把链表销毁了。(链表已经不存在)\n\r");
}

//打印链表信息
ElemTypeVoid Print_List(LinkList head)
{
LinkList p;
ElemType n = 0;

if(head == NULL)
{
printf("\n\r 您需要创建一个链表,我不能为你打印。\n\r");
return;
}

p = head->next;
while(p!=NULL)
{
printf("%4d",p->value);
p = p->next;
n++;
if(n%5 == 0)
printf("\n\r");//只是为了看代码输出整洁
}
printf("\n\r链表总共%d个元素\n\r", n);

}

//菜单
ElemTypeVoid menu()
{
printf("\n\r/****************************/\n\r");
printf("\n\r 1. 创建链表Create_List() \n\r");
printf("\n\r 2. 链表插入Insert_List() \n\r");
printf("\n\r 3. 链表删除Delete_List() \n\r");
printf("\n\r 4. 链表销毁Destroy_List()\n\r");
printf("\n\r 5. 链表打印Print_List()  \n\r");
printf("\n\r 0. 退出          \n\r");
printf("\n\r/****************************/\n\r");
}


//主函数
void main()
{
LinkList head;
ElemType i = 1, n = 0;


while ( 1 )
{
menu();
printf("输出你的选项:n =");
   scanf("%d",&i);
switch( i ) 
{
case 1:
printf("请创建您的链表,您想创建多大的链表.\n");
printf("请输入您创建的个数 n = \n");
scanf("%d", &n);
  head = Create_List(n);
break;

case 2:
Insert_List(head);
break;

case 3:
Delete_List(head);
break;

case 4:
Destroy_List(head);
break;

case 5:
Print_List(head);
break;

case 0:
return;

default:
printf("您在逗我吗?I am really silly.您再试试吧!\n\r");
break;
}
        }
}

二.内核链表 内核链表是一种链表,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、付费专栏及课程。

余额充值