C语言实现单链表-02版
我们在C语言实现单链表-01版中实现的链表非常简单;
但是它对于理解单链表是非常有帮助的,至少我就是这样认为的;
简单的不能再简单的东西没那么实用,所以我们接下来要大规模的修改啦;
Problem
1,要是数据很多怎么办,100000个节点,这个main函数得写多长啊。。。
2,这个连接的方式也太土啦吧!万一某个节点忘记连接下一个怎么办。。。
3,要是我想知道这个节点到底有多长,难道每次都要从头到尾数一遍嘛。。。
4,要是我想在尾部添加一个节点,是不是爬也要爬到尾部去啊。。。
这个是简单版中提出的问题,接下来就解决它们;
Solution
首先,定义我们的数据域,它既然是一个人,那么就把身高和体重放到人身上吧;
typedef struct person_ {
int hight;
int weight;
}Person;
再继续定义我们的节点;
typedef struct node_ {
Person * data;
struct node_ * next;
}Node;
好啦!接下来我们希望有一个函数帮我们把节点连接起来,并且把数据域(人得身高体重)填入;
Node * create_node(void *data)
{
Node * tmp = (Node*)malloc(sizeof(Node));
if(tmp) {
tmp->data = data;
tmp->next = NULL;
}
return tmp;
}
它的意图很明显,只要给我一个人的身高和体重我就返回一个节点给你;
我们到这里可以先测试一下自己的程序看看有什么问题没,然后再继续;
int main(void)
{
Person a = { , };
Node * A = create_node(&a); Person b = { , };
Node * B = create_node(&b); Person c = { , };
Node * C = create_node(&c); A->next = B;
B->next = C; Node * we=NULL;
we = A; while(we != NULL) {
printf("%d--%d\n",we->data->hight,we->data->weight);
we = we->next;
}
return ;
}
看看结果:

似乎比前一个版本有所进步;
但是可以怎么说,链表的内脏我们写进去啦!但是它的肠子还露在外边,恶心吧:);
如果不能,理解的话,你请看在main函数中那些恶心的步骤任然在。。。;
好吧!解决它;
typedef struct link_list_ {
Node * head;
Node * tail;
int size;
}Link_List;
为了更好的管理我们的链表,我们需要知道它的头和尾还有它到底有多长;
因此,上面的结构体应该是暂时可以这么写的;
好吧!有了结构体,接下来就是初始化它啦!它就像其他int,char类型一样使用前一样需要初始化;
(就像哪个婴儿都喜欢喝奶一样哈)
Link_List * init_list(void)
{
Link_List * lst = (Link_List*)malloc(sizeof(Link_List));
lst->head = lst->tail = NULL;
lst->size = ;
return lst;
}
初始化后,我们需要给它添加一些节点啦;
这里链表的管理的方式很简单,它只记住链表的头和尾还有长度,不关心你在里面存入什么数据;
(就好比,学校的宿舍管理员,它只知道拿着宿舍大门的钥匙,才不管你在宿舍里怎么睡觉---其实有些管得很严呢:);
好啦!我们需要一个插入节点的函数(让我们的肠子跟随内脏一起进去吧,不要再继续恶心啦
我们的插入数据函数如下:
void insert(Link_List *lst,void *data)
{
Node * new_node = create_node(data);
if(lst->size == ) {
lst->tail = new_node; //tip:01
} new_node->next=lst->head;
lst->head = new_node;
lst->size++;
}
然后可以测试我们的代码啦!
int main(void)
{
Link_List * root = init_list(); Person a = { , };
Person b = { , };
Person c = { , }; insert(root,&a);
insert(root,&b);
insert(root,&c); Node * we=NULL;
we = root->head; while(we != NULL) {
printf("%d--%d\n",we->data->hight,we->data->weight);
we = we->next;
}
return ;
}
看看结果:

注意看,我们的输出次序与前面的次序不一样啦!
怎么回事呢?思考一下会;
这个问题先不告诉大家,接下来看看我们的链表是不是管理正常;
首先,看看这个链表现在到底它到底有多长呢;
{
Link_List * root = init_list();
Person a = { , };
Person b = { , };
Person c = { , };
insert(root,&a);
insert(root,&b);
insert(root,&c);
Node * we=NULL;
we = root->head;
while(we != NULL) {
printf("%d--%d\n",we->data->hight,we->data->weight);
we = we->next;
}
printf("The size of the link-list is : %d\n",root->size);
return ;
}
看看结果:

再看看,尾部和头部节点,是不是都能很轻松的告诉我们呢;
printf("The size of the link-list is : %d\n",root->size);
printf("The head guy is %d--%d\n",root->head->data->hight,root->head->data->weight);
printf("The last guy is %d--%d\n",root->tail->data->hight,root->tail->data->weight);
return ;
好啦!再看结果:

好啦!结果正如我们期待的;
观察发现,我们的最后两句是root->head->data->hight等等,非常长,这里给大家介绍一种简单的写法;
#define GO_H(RT,HW) (RT->head->data->HW) //GO_H:go head; RT:Root; HW: Hight,Weight
#define GO_T(RT,HW) (RT->tail->data->HW) //GO_T:go tail; RT :Root; HW: Hight,Weight
然后我们的代码就可以这样写啦!
printf("The head guy is %d--%d\n",GO_H(root,hight),GO_H(root,weight));
printf("The last guy is %d--%d\n",GO_T(root,hight),GO_T(root,weight));
好啦!基本上完成啦!
所有代码如下:
#include <stdio.h>
#include <stdlib.h> #define GO_H(RT,HW) (RT->head->data->HW) //GO_H:go head; RT:Root; HW: Hight,Weight
#define GO_T(RT,HW) (RT->tail->data->HW) //GO_T:go tail; RT :Root; HW: Hight,Weight typedef struct person_ {
int hight;
int weight;
}Person; typedef struct node_ {
Person * data;
struct node_ * next;
}Node; typedef struct link_list_ {
Node * head;
Node * tail;
int size;
}Link_List; Node * create_node(void *data)
{
Node * tmp = (Node*)malloc(sizeof(Node));
if(tmp) {
tmp->data = data;
tmp->next = NULL;
}
return tmp;
} Link_List * init_list(void)
{
Link_List * lst = (Link_List*)malloc(sizeof(Link_List));
lst->head = lst->tail= NULL;
lst->size = ;
return lst;
}
void insert(Link_List *lst,void *data)
{
Node * new_node = create_node(data);
if(lst->size == ) {
lst->tail = new_node; //tip:01
} new_node->next=lst->head;
lst->head = new_node;
lst->size++;
}
int main(void)
{
Link_List * root = init_list(); Person a = { , };
Person b = { , };
Person c = { , }; insert(root,&a);
insert(root,&b);
insert(root,&c); Node * we=NULL;
we = root->head; while(we != NULL) {
printf("%d--%d\n",we->data->hight,we->data->weight);
we = we->next;
}
printf("The size of the link-list is : %d\n",root->size);
printf("The head guy is %d--%d\n",GO_H(root,hight),GO_H(root,weight));
printf("The last guy is %d--%d\n",GO_T(root,hight),GO_T(root,weight));
return ;
}
但是我不得不告诉你,它还有很多缺陷;
我们下次再讨论;
C语言实现单链表-02版的更多相关文章
- C语言实现单链表-03版
在C语言实现单链表-02版中我们只是简单的更新一下链表的组织方式: 它没有更多的更新功能,因此我们这个版本将要完成如下功能: Problem 1,搜索相关节点: 2,前插节点: 3,后追加节点: 4, ...
- C语言实现单链表-01版
单链表的应用非常广,它可以实现栈,队列等: Problem 我对学习任何东西都希望能找到尽可能简单的例子,而不是看起来好高大上的: 对链表这样简答的数据结构,有些书也是写得太过“完美”啦: 初学者很难 ...
- C语言实现单链表-04版
前面的版本似乎没能让项目经理满意,他还希望这个链表有更多的功能: 我们接下来要解决几个比较简单的功能: Problem 1,更加友好的显示数据: 2,能够通过名字删除节点: Solution 首先我们 ...
- C语言实现单链表,并完成链表常用API函数
C语言实现单链表,并完成链表常用API函数: 1.链表增.删.改.查. 2.打印链表.反转打印.打印环形链表. 3.链表排序.链表冒泡排序.链表快速排序. 4.求链表节点个数(普通方法.递归方法). ...
- C语言实现单链表节点的删除(带头结点)
我在之前一篇博客<C语言实现单链表节点的删除(不带头结点)>中具体实现了怎样在一个不带头结点的单链表的删除一个节点,在这一篇博客中我改成了带头结点的单链表.代码演示样例上传至 https: ...
- C/C++语言实现单链表(带头结点)
彻底理解链表中为何使用二级指针或者一级指针的引用 数据结构之链表-链表实现及常用操作(C++篇) C语言实现单链表,主要功能为空链表创建,链表初始化(头插法),链表元素读取,按位置插入,(有序链表)按 ...
- 「C语言」单链表/双向链表的建立/遍历/插入/删除
最近临近期末的C语言课程设计比平时练习作业一下难了不止一个档次,第一次接触到了C语言的框架开发,了解了View(界面层).Service(业务逻辑层).Persistence(持久化层)的分离和耦合, ...
- 一起talk C栗子吧(第十二回:C语言实例--单链表一)
各位看官们,大家好.从今天開始,我们讲大型章回体科技小说 :C栗子.也就是C语言实例.闲话休提, 言归正转. 让我们一起talk C栗子吧! 看官们,上一回中咱们没有说详细的样例,并且是说了样例中的文 ...
- C语言实现单链表(不带头结点)节点的插入
对单链表进行增删改查是最主要的操作.我在上一篇博客<C语言实现链表节点的删除>实现了删除单链表中的某个节点. 这里我们要来实如今某个位置插入节点.演示样例代码上传至https://gith ...
随机推荐
- scala学习:apply方法
摘抄两段话: 在明确了方法调用的接收者的情况下,若方法只有一个参数时,调用的时候就可以省略点及括号.如 " to ",实际完整调用是 ".to()".但 &qu ...
- Intellij Idea使用技巧、快捷键
1.Idea设置字体大小:file -> setting -> editor -> colors&font -> save as并自定义 -> font -> ...
- 一个使用高并发高线程数 Server 使用异步数据库客户端造成的超时问题
现象 今天在做一个项目时, 将 tomcat 的 maxThreads 加大, 加到了 1024, tomcat 提供的服务主要是做一些运算, 然后插入 redis, 查询 redis, 最后将任务返 ...
- 面试知识点总结之Java语言
1.如果某个对象出现在字符串表达式中,如System.out.println(this+".class");,则会自动调用this.toString() 2.所有的类都是在对其第一 ...
- EF 6 for mysql
1. NuGet安装 MySql.Data.MySql.Data.Entity 2.安装Entity Framework 6 Tools for Visual Studio 2012 & 20 ...
- 数字电路-异同步 复位 线与 oc门
1.同步电路和异步电路的区别是什么? 异步电路:主要是组合逻辑电路,用于产生地址译码器.FIFO或RAM的读写控制信号脉冲,但它同时也用在时序电路中,此时它没有统一的时钟,状态变化的时刻是不稳定的,通 ...
- Nginx虚拟目录支持PHP配置
感谢作者:http://blog.csdn.net/fangaoxin/article/details/7030139 location ~ ^/test/.+\.php$ { alias /var/ ...
- Android之Fragment学习总结(1)
对于Fragment的学习: 近日初步学习了Fragment这以特殊的组件,其依托与一个Activity,与Activity的生命周期息息相关,为其设置的视图只有当其关联到一个Activity才会起效 ...
- MVC过滤器
MVC的每一个请求都会给相应的控制器的对应行为方法处理,那么想在这些处理的前 前后后增加一些额外的逻辑处理,因此过滤器的作用就来了 MVC支持的过滤器类型有四种,分别是:Authorization(授 ...
- [转]框架模式 MVC 在Android中的使用
算来学习Android开发已有2年的历史了,在这2年的学习当中,基本掌握了Android的基础知识.越到后面的学习越感觉困难,一来是自认为android没啥可学的了(自认为的,其实还有很多知识科学), ...