什么是链表

简单理解为链表的功能与数组功能相似用来存储数据,链表作为一种基本的数据结构在程序开发过程当中经常会使用到。对C语言来说链表的实现主要依靠结构体(可以存储多种数据类型)和指针,所以本文相关内容和程序需要有C语言当中指针和结构体的基础。

为什么使用链表

1、解决数组无法存储多种数据类型的问题。

2、解决数组中,元素个数无法改变的限制。

3、数组移动元素的过程中,要对元素进行大范围的移动,很耗时间,效率也不高。

链表的组成

1、链表由节点组成。

2、节点由值域与指针域组成。

3、还需要一个头指针指向链表(例如一个指针指向一个数组,那么数组名也可以代表此数组的首地址)

4、链表的基本表示

struct node //表示图片中的体

{

int num;

char a;

struct node *next; //指向下一个相同数据类型的结构体,next存放下一个结点的地址

}

> head头指针指向头结点,其中头结点的next指针指向下一个节点的头,一次类推直到最后一个节点的尾指针指向NULL(空指针)时离链表结束。

(这里的体是结构体类型,next是指向下一个结点的指针,结点的组成:数据域(体是数据域的一种体现)+(指针域) )

链表的特点

1、链表结点可以连续,可以不连续存储。

2、结点的逻辑顺序与物理顺序可以不一致。

3、表可扩充。

逻辑顺序与物理顺序的理解

可以使用的存储空间

解释:各个结点的物理存储位置可能不是连续的,a0后面是a2而不是a1,但是每个结点的尾地址都是按照逻辑顺序指向下一个结点的。(意思就是说我有10个抽屉,每个抽屉编号1~10,但是这10个抽屉不是按顺序摆放,将扑克牌A到10一次按抽屉顺序放入10个抽屉里,每次取按顺序取出,例如第一个抽屉在第1层,里面是A,接下来要去2但是存放2的抽屉在第5层因此要去第5层取2)

怎么插入一个节点

在头结点的后面插入一个节点

插入一个中间节点

在头节点前面插入节点(头插)

尾插

1、

将一个新的结点插入到最后一个节点的后面,先将前一个尾结点的地址指向新结点的地址P,然后再将新结点的指针域改成NULL。

2、

头插入:新建一个结点他的指针域指向头结点的头地址,修改之后在将链表的头地址指向新建结点的地址这样新建结点就成为链表新的头节点

**

对于链表中&head,一级指针,二级指针的总结

分析:

1,只要是修改头指针则必须传递头指针的地址,否则传递头指针值即可(即头指针本身)。这与普通变量类似,当需要修改普通变量的值,需传递其地址,否则传递普通变量的值即可(即这个变量的拷贝)。使用二级指针,很方便就修改了传入的结点一级指针的值。 如果用一级指针,则只能通过指针修改指针所指内容,却无法修改指针的值,也就是指针所指的内存块。所以创建链表和销毁链表需要二级指针或者一级指针引用。

2,不需要修改头指针的地方用一级指针就可以了,比如插入,删除,遍历,清空结点。假如头指针是L,则对L->next 及之后的结点指针只需要传递一级指针。

3,比如一个结点p,在函数里要修改p的指向就要用二级指针,如果只是修改p的next指向则用一级指针就可以了

~~~*以下代码均是对于无表头结点的操作*~

**

写头插时应该先想好代码的思路:

创建结点元素

创建空链表

创建结点

插入节点函数

编译链表

//创建结点元素

//创建空链表

//创建结点

//插入节点函数

//编译链表

#include #includestruct node //构思结点元素

{

int num;

char name[20];

int age;

struct node * next;

};

typedef struct node Node;

typedef Node * Link;

void creat_list(Link * head) //创建链表初始化为空表

{

*head = NULL;

}

void is_malloc_ok(Link new_node) //判断创建的结点是否成功分配了空间

{

if(NULL == new_node)

{

printf("malloc error!\n");

exit(-1);

}

}

void creat_new_node(Link * new_node)

{

*new_node = (Link)malloc(sizeof(Node));

is_malloc_ok(*new_node);

}

void display(Link head) //打印链表

{

Link p;

p = head;

if(NULL == head)

{

printf("Link is empty!\n");

return;

}

while(NULL != p)

{

printf("%d\n",p->num);

p = p->next;

}

}

void insert_node_head(Link * head,Link new_node)

{

new_node->next = *head; //通过图2进行理解这里的地址转换

*head = new_node;

}

int main()

{

int i = 0;

Link head = NULL; //初始化避野指针

Link new_node = NULL;

creat_list(&head); //**head是头地址,对于链表创建是对于地址的操作,

因为链表名本身代表链表首地址,因此在调用函数操作传入一个二阶地址,

通过解引用(*head)来操作指针head**

for(i=0; i < 10; i++)

{

creat_new_node(&new_node);

new_node->num = i + 1;

insert_node_head(&head,new_node);

}

display(head);

return 0;

}

写尾插法的代码

void insert_node_tail(Link * head,Link new_node)

{

Link p; //尾插需要找到上一个结点的尾指针,因此需要一个变量定义此指针

p = *head;

if(NULL == *head) //链表为空时先插入第一个结点

{

*head = new_node;

new_node->next = NULL;

}

else //当P不为空时插入第二个结点

{

while(NULL != p->next)

{

p = p->next;

}

p->next = new_node; //尾插让新结点的next都是NULL,头指向上一个结点

new_node->next = NULL;

}

**

总结

由上面的例子以及比较,我们可以看见:

1、头插法相对简便,但插入的数据与插入的顺序相反;

2、尾插法操作相对复杂,但插入的数据与插入顺序相同。

**

随机数倒叙排列

int insert_node_mid_sort(Link * head,Link new_node)

{

Link p,q;

p = q = *head;

if(NULL == *head) //空表时将第一个结点插入此时头结点地址不为空

{

*head = new_node;

new_node->next = NULL;

}

else if((*head)->num > new_node->num) //当结点的num>头结点时将他插入到头结点前面

{

new_node->next = *head;

*head = new_node;

}

else

{

while(p != NULL && p->num < new_node->num) //参考下图分析代码 (&&有一个不满足条件时就跳出代码执行下面的代码)

{

q = p;

p = p->next;

}

q->next = new_node;

new_node->next = p;

}

}

只需要将6的头插入到5的尾,6的尾巴插入到7的头就可以了。

while(p != NULL && p->num < new_node->num)

因为此时链表中已经有了结点,所以P不是NULL,切有num,此时5<6,

p,q,head,地址相同,此时p指向下一个结点

q = p;

p = p->next;

q->next = new_node;

new_node->next = p;

此时将new_node的头地址,尾地址互换插入到链表中去,

**

将一个num添加到一个结点的前面

void insert_node_mid_front(Link * head,Link new_node,int loc)

{

Link p,q;

p = q = *head;

if((*head)->num == loc)

{

new_node->next = *head;

*head = new_node;

}

else

{

while(p != NULL && p->num != loc)

{

q = p;

p = p->next;

}

q->next = new_node;

new_node->next = p;

}

} //此代码原理同上只是新建一个loc

#if//在主函数中打印

printf("\n\n");

create_node(&new_node);

new_node->num = 100;

printf("please input loc:\n");

scanf("%d",&loc);

insert_node_mid_front(&head,new_node,loc);

display(head);

删除结点

void delete_node(Link * head,int num_del)

{

Link p, q;

p = q = *head;

if(NULL == *head)

{

printf("Link is empty!\n");

return;

}

else if((*head)->num == num_del)

{

*head = (*head)->next ;

free(p);

return;

}

else

{

while(NULL != p && p->num != num_del)

{

q = p;

p = p->next;

}

if(NULL == p)

{

printf("no such node!\n");

}

else

{

q->next = p->next;

free(p);

}

}

}

**

查找结点

Link search_node(Link head,int num_serch)

{

Link p;

p = head;

if(NULL == head)

{

printf("Link is empty!\n");

return NULL;

}

else

{

while( p != NULL && p->num != num_serch)

{

p = p->next;

}

if(NULL == p)

{

return NULL;

}

else

{

return p;

}

}

}

**

对于如何使用1级指针或者2级指针参考博客

待续…

c语言中头结点不为零怎么写,C语言不带表头结点的单链表操作相关推荐

  1. C语言中头文件和源文件的注意事项

    C语言中头文件和源文件的注意事项 文章目录 C语言中头文件和源文件的注意事项 0.前言 1.实现步骤 1.1 拆分前 1.2 拆分后 2.总结 2.1头文件内容 2.2 源文件(.c)内容 2.3 函 ...

  2. C语言中头文件怎么写?(本文来源网络,由黑乌鸦进一步完善)

    c语言头文件怎么写?我一直有这样的疑问,但是也一直没去问问到底咋回事:所以今天一定要把它弄明白! 其实学会写头文件之后可以为我们省去不少事情,可以避免书写大量的重复代码.有利于整理思路.使代码脉络更加 ...

  3. 数据结构:试设计一个算法,改造一个带表头结点的双向链表,所有结点的原有次序保持在各个结点的右链域rLink中,并利用左链域ILink把所有结点按照其值从小到大的顺序连接起来

    题目 试设计一个算法,改造一个带表头结点的双向链表,所有结点的原有次序保持在各个结点的右链域rLink中,并利用左链域ILink把所有结点按照其值从小到大的顺序连接起来 分析 Template < ...

  4. 单链表操作实现getelem_c语言实现--带头结点单链表操作

    可能是顺序表研究的细致了一点,单链表操作一下子就实现了.这里先实现带头结点的单链表操作. 大概有以下知识点. 1;结点:结点就是单链表中研究的数据元素,结点中存储数据的部分称为数据域,存储直接后继地址 ...

  5. 不带头结点的C语言单链表操作,头插法及尾插法

    接上篇带头结点的单链表操作,不带头节点真的比带头结点的麻烦好多,主要是我自己指针指的有点晕,搞了这几天的不带头结点的单链表,算是弄清楚指针的玩法了..老样子上代码. # include "s ...

  6. c语言浮点变量是什么意思,C语言中说的浮点型是什么意思呢 C语言的浮点数是什么...

    导航:网站首页 > C语言中说的浮点型是什么意思呢 C语言的浮点数是什么 C语言中说的浮点型是什么意思呢 C语言的浮点数是什么 相关问题: 匿名网友: 就是这个数就像有一个飘动的小数点,也就是我 ...

  7. 不带头结点的单链表操作

    不带头结点的单链表操作,包括插入.遍历.统计结点数等,要求写出数据结构算法思想及C语言实现函数 本文为博主原创文章,未经博主允许不得转载. 版权为陈博超所有,第一次于2021年06月22日发表于BLO ...

  8. 详解C语言中头文件的作用

    大家好,先做个自我介绍,我是天蓬,欢迎阅读本篇博文. 由于本人理解能力不是很好,阅读他人文章时,常常看得晕头晕脑,这让我很是头疼,我想,世界上一定还有和我一样的人(哈哈,不是说你么笨哦).所以,我将会 ...

  9. C语言中头文件包含的处理原则

    很多事不深入以为自己懂了,但真正用到项目上,才发现了问题.曾以为自己写C语言已经轻车熟路了,特别是对软件文件的工程管理上,因为心里对自己的代码编写风格还是有自信的.(毕竟刚毕业时老大对我最初的训练就是 ...

最新文章

  1. 安全的 ActiveMQ
  2. AndroidAsync
  3. php通过MongoClient扩展连接mongodb库的两点建议
  4. 回文子串—leetcode647
  5. URLScan工具配置方法第1/2页
  6. django权限系统实现步骤_在django中实现一个简单的权限管理
  7. java常见的内存溢出
  8. 英文聊天常用缩写单词
  9. CentOS Linux 7编译安装Redis
  10. c语言node类型_高阶宏的妙用技法,C语言宏你所不知道的聪明技巧
  11. lua 去除小数点有效数字后面的0_【物联网学习番外篇】Lua脚本编程扫盲
  12. 应用内收费--商品列表--子龙山人
  13. oracle有rtf函数,Delphi中对Oracle存取RTF文档(作者:苏涌)
  14. Windows 本地安全策略
  15. 概念学习和一般到特殊序
  16. 微信小程序授权用户绑定手机号
  17. 群发邮箱的软件哪个好?2021协议邮件群发软件推荐?
  18. wifi文件传输linux,wifi挂载Linux文件系统
  19. Ubuntu Server 安装Nginx 实例
  20. sd卡格式化怎么恢复?

热门文章

  1. python怎么保存文件代码_Python文件读写保存操作的实现代码
  2. unity fixedupdate_unity相关
  3. JAVA窗口sin值_大厂经典笔试题—LeetCode03无重复字符的最长子串(滑动窗口)
  4. 整理计算机网络参考模型知识
  5. Git和GitHub使用教程
  6. 启动mysql会遇到的问题_MySQL学习(一)——启动和登录MySql遇到的问题及解决
  7. .bat脚本自动yes_第四章: Python脚本获取聚宽(JQData)免费行情数据
  8. 二叉树的非递归遍历(统一的模板)
  9. 第12章:项目采购管理-章节真题
  10. 笔记-高项案例题-2017年下-整体管理-变更管理