牢骚:本篇博客两个星期前已经存为草稿,鉴于发生一些糟糕的事情,今天才基本完成。本人6月份应届毕业生一枚,毕业后当天来到帝都,之后也非常顺利,面试了俩家公司都成功了。一家做C++方面电商ERP,一家做wifi模块,觉得第二家公司小,薪资低,但是觉得好玩就去了。同时,在学校也喝了不少鸡汤,觉得公司小怎么了。然而去了不到20天,公司被深圳一家公司收购了,公司动员我去深圳,我尼玛我才来20多天啊,有木有?而且感觉公司做这么大的决定都是随时拍板的吗?

原本以为一个公司的生命力强到可以忽略的概率,然而当自己真实的遇到这一切,才知道这个社会有多残忍,公司的生存可能比一个员工的生存更要困难。

接下来就是找工作了,跑呀,找呀。。。。。。。。           一路被忽略,一路被放鸽子,一路被无视。。。。。。。   心里五味杂陈。。。。。。。。。

so,可能我还是太菜了,这种玩计算机的心态,也许会被生活玩,唯有认真拼命的学习也许能够拯救我的颓势。

感谢seven,严厉也好,鼓励也好,短短的一个月,您教会了我许多,感谢您的知遇之恩!愿你们去深圳一切顺利!待倔强的我在北京玩上一阵!

————————————————————————————————————————————————————————————————————————————————

链表是数据结构中比较基础也是比较重要的类型之一,那么有了数组,为什么我们还需要链表呢!或者说设计链表这种数据结构的初衷在哪里?

这是因为,在我们使用数组的时候,需要预先设定目标群体的个数,也即数组容量的大小,然而实时情况下我们目标的个数我们是不确定的,因此我们总是要把数组的容量设置的很大,这样以来就浪费了很多的空间。另外,数组在进行插入操作和删除操作的时候,在插入或者删除制定元素之后,我们往往需要进行循环移位,这增加了我们的线性开销。

正是由于以上的两种主要原因,链表被设计出来用于一般表的操作。为了避免上面描述数组的两种弊端,我们希望链表有一下的特点

1 可以灵活的扩展自己的长度。

2 存储地址不连续,删除或者插入操作的时候不需要循环移位。

要实现以上两个特点,我们需既要保证每个节点的独立性,又要保存相邻两个节点的联系。

为此,链表一般被设计为下面的形式。

Node--->Node---->Node

链表是由一个一个的节点组成的,可以方便和自由的插入未知个Node,前一个节点中用指针保存着下一个节点的位置,这样以来便顺利的完成了我们对链表的两点期望,但是唯一的缺点是增加了额外的空间消耗。

————————————————————————————————————————————————————————————————————————————

链表的定义:

链表的定义一般使用结构体,在看《数据结构与算法分析》这本书的时候发现,书中频繁的使用typedef的关键字,结果真的很棒不仅保持的代码的整洁程度,也让我们在下面的编码过程中少见了很多烦人的指针(当然指针还是一直存在的)。所以这里也借用了书中的定义方法。

  1. struct Node;
  2. typedef struct Node* PtrNode;
  3. typedef PtrNode Position;
  4. typedef PtrNode List;
  5. struct Node{
  6. int Value;
  7. PtrNode Next;
  8. };

下面接着书写一个建立链表的函数,输入每个节点的值,直到这个值是-1的时候函数结束。

在这个里面,我以前一直搞不明白为什么需要定义三个Node *,现在终于了解了,最终还是复习了指针的内容明白的,这里说一下指针实现链表对指针的操作很频繁,需要比较扎实的掌握了指针之后,在来看链表会轻松很多。在下面的一段程序里,我分别定义了head/p/tmp这三个指向节点结构体的指针,head的主要作用就像一个传销头目,他会主动联系上一个下线p,然后他就什么也不干了,p接着去发展一个又一个的下线tmp,结果一串以head为首的链表就出来了。

起先,我总觉得有了head,为什么还要p,这是因为如果直接使用head去指向下一个节点,head的位置也是不断在移动的,即它永远处于链表的尾端,这样当我们返回链表的时候,其实是空值。所以,我们需要p这个中转环节。(其实,这种做法在指针中非常普遍,大部分有返回指针类型的函数中,都会首先定义一个指针变量来保存函数的传入的参数,而不是对参数直接进行操作)。

  1. /*
  2. 函数功能:创建一个链表
  3. 函数描述:每次输入一个新的整数,即把新增加一个节点存放该整数,
  4. 当输入的整数为-1时,函数结束。
  5. */
  6. List create()
  7. {
  8. int n=;
  9. Position p,head,tmp;
  10. head=NULL;
  11. tmp=malloc(sizeof(struct Node));
  12. if(tmp==NULL)
  13. {
  14. printf("tmp malloc failed!\n");
  15. return NULL;
  16. }
  17. else
  18. {
  19. p=tmp;
  20. printf("please input the first node's message!\n");
  21. scanf("%d",&(tmp->Value));
  22. }
  23. while(tmp->Value!=-)
  24. {
  25. n+=;
  26. if(n==)
  27. {
  28. head=p;
  29. tmp->Next=NULL;
  30. }
  31. else
  32. {
  33. p->Next=tmp;
  34. }
  35. p=tmp;
  36. tmp=malloc(sizeof(struct Node));
  37. printf("please input the %d node!\n",n+);
  38. scanf("%d",&(tmp->Value));
  39. }
  40. p->Next=NULL;
  41. free(tmp); //free函数free掉的只是申请的空间,但是指针还是依然存在的。
  42. tmp=NULL;
  43. return head;
  44.  
  45. }

接下来,在写一个删除链表节点的函数,输入一个整数然后遍历链表节点,当链表节点的值与该整数相等的时候,即把该节点删除。

在完成这个函数首先一定要把这个过程思考清楚,不可否认我之前是一个上来就敲代码的人,看了《剑指offer》感觉这种习惯是程序员的大忌,甚至还想写一篇博客,名字都想好了《程序员的自我修养之思考在前,代码在后》。其实想想也是,我们写程序的目的是为了解决问题,而不是为了简单的写程序,纯粹的让程序跑起来大概只会在上学那会存在吧!真实的程序开发中需要考虑几乎所有 能想到的实际问题,所以无论程序再下,一要学会先思考清楚,再下笔写程序。

关于这个函数,我们要想到的是:

1 如果链表为空,我们该怎么做,当然是直接返回。

2 如果要删除的元素为头节点该怎么办?

3 如果要删除的元素为尾节点该怎么办?

当注意到以上三个部分,我们的程序就可能避免掉了输入链表为空,程序直接崩溃的现象,也可以避免删除元素值为头节点时删不掉的尴尬。我们的程序就有了一定的鲁棒性。

下面着重考虑链表的删除的实现:

list:      Node_a->Node_b->Node_c->Node_d;

list        tmp         p

------->              tmp->Next=p->Next;

list:       Node_a->Node_b----------->Node_d

free(p)

假设我们要删除的节点为上图的Node_c;假设我们能够找到Node_c的前一个位置tmp和被删除节点位置p的话;这个时候我们只需要执行tmp->Next=p->Next即可。

只要完成上面的分析以及考虑到各种情况,我们完成下面的代码就水到渠成了。

  1. /*
  2. 函数功能:删除链表中指定值的节点(如果存在多个,只删除第一个)
  3. 本例中输入一个整数,删除链表节点值为这个整数的节点。
  4. */
  5. List DeleteNode(List list)
  6. {
  7. Position p,tmp;
  8. int value;
  9. if(list==NULL)
  10. {
  11. printf("The list is null,function return!\n");
  12. return NULL;
  13. }
  14. else
  15. {
  16. printf("please input the delete Node's value:\n");
  17. scanf("%d",&value);
  18. }
  19. p=list;
  20. if(p->Value==value)
  21. {
  22. list=p->Next;
  23. free(p);
  24. p=NULL;
  25. return list;
  26. }
  27. while(p!=NULL&&p->Value!=value)
  28. {
  29. tmp=p;
  30. p=p->Next;
  31. }
  32. if(p->Value==value)
  33. {
  34. if(p->Next!=NULL){
  35. tmp->Next=p->Next;
  36. }
  37. else
  38. {
  39. tmp->Next=NULL;
  40. }
  41. free(p);
  42. p=NULL;
  43. }
  44. return list;
  45.  
  46. }

关于链表的使用场景分析:

链表在程序开发中用到的频率还是非常高的,所以在高级语言中往往会对链表进行一些实现,比如STL中list以及Java中也有类似的东西。在目前的服务器端开发,主要运用链表来接收一些从数据中取出来的数据进行处理。

即使你不知道链表的底层实现,仍然可以成功的运用STL里面的现成的东西。但是作为一个学习者,我觉得会使用和从底层掌握仍然是两个不同的概念,linux之父说:“talk is less,show you code”。

以下的程序,用链表模拟了一个电话通讯录的功能,包括添加联系人,查找联系人,以及删除联系人。

PS:关于鲁棒性,程序中最大的危险是使用了gets这个函数,目前先保留使用gets,等待找到工作之后在做进一步的程序完善。

  1. /**************************************************************************
  2. Programe:
  3. This is a phone list write by list
  4. The programe is just prictise for list
  5. Author: heat nan
  6. Mail:964465194@qq.com
  7. Data:2015/07/27
  8. **************************************************************************/
  9. #include<stdio.h>
  10. #include<string.h>
  11. #include<stdlib.h>
  12. #define N 25
  13. #define M 15
  14. struct node;
  15. typedef struct node* p_node;
  16. typedef p_node List;
  17. typedef p_node Position;
  18. typedef struct node** PList;
  19. struct node{
  20. char name[N];
  21. char number[M];
  22. Position next;
  23. };
  24. int JudgeNameExist(List list,char* name);
  25. void AddPerson(PList list);
  26. void PrintList(List list);
  27. List FindPerson(List list);
  28. List FindPersonByName(List list,char* name);
  29. int AddPersonByName(PList list,List node);
  30. int DeletePersonByName(PList list,char* name);
  31. void DeletePerson(PList list);
  32. int main()
  33. {
  34. List list=NULL;
  35. Position p;
  36. char cmd[];
  37. while()
  38. {
  39. printf(" MAIN \n");
  40. printf(" ******* 1 add a person *******\n");
  41. printf(" ******* 2 show the phone list *******\n");
  42. printf(" ******* 3 find from phone list *******\n");
  43. printf(" ******* 4 delete from phone list *******\n\n\n");
  44. printf("Please input the cmd number:\n");
  45. gets(cmd);
  46. switch(cmd[])
  47. {
  48. case '':
  49. AddPerson(&list);
  50. break;
  51. case '':
  52. PrintList(list);
  53. break;
  54. case '':
  55. FindPerson(list);
  56. break;
  57. case '':
  58. DeletePerson(&list);
  59. break;
  60. default:
  61. printf("wrong cmd!\n");
  62. break;
  63.  
  64. }
  65.  
  66. }
  67. return ;
  68. }
  69. /*
  70. Function:判断要添加的联系人名称是否已经存在于电话簿中.
  71. Input: List 电话列表,name 要添加的联系人的姓名.
  72. Return: 已经存在返回1,不存在返回0.
  73. */
  74. int JudgeNameExist(List list,char* name)
  75. {
  76. if(FindPersonByName(list,name)!=NULL)
  77. return ;
  78. else
  79. return ;
  80. }
  81. /*
  82. Function:根据输入的姓名查找联系人的信息节点
  83. Input: 要输入的电话列表list,姓名name
  84. Return: 返回查找到的节点
  85. */
  86. List FindPersonByName(List list,char* name)
  87. {
  88. while(list!=NULL)
  89. {
  90. if(strcmp(list->name,name)==)
  91. break;
  92. list=list->next;
  93. }
  94. return list;
  95. }
  96. /*
  97. Function:根据姓名添加新的联系人到联系人列表
  98. Input: 指向联系人列表地址的指针, 新用户节点
  99. Return: 添加成功返回1,添加失败返回0
  100. */
  101. int AddPersonByName(PList list,List node)
  102. {
  103. if(node==NULL)
  104. {
  105. printf("the node is NULL!\n");
  106. return ;
  107. }
  108. if(*list==NULL)
  109. {
  110. *list=node;
  111. return ;
  112. }
  113. List pHead=*list;
  114. while(pHead->next!=NULL)
  115. pHead=pHead->next;
  116. pHead->next=node;
  117. return ;
  118. }
  119. void AddPerson(PList list)
  120. {
  121. Position tmp;
  122. Position p_head;
  123. tmp=(struct node*)malloc(sizeof(struct node));
  124. char name[N];
  125. char number[M];
  126. if(tmp==NULL)
  127. {
  128. printf("malloc the tmp node failed in function add person!\n");
  129. }
  130. else
  131. {
  132.  
  133. printf("please input the name:\n");
  134. gets(name);
  135. printf("please input the number:\n");
  136. gets(number);
  137. strcpy(tmp->name,name);
  138. strcpy(tmp->number,number);
  139. tmp->next=NULL;
  140. }
  141. if(JudgeNameExist(*list,name)==)
  142. {
  143. free(tmp);
  144. printf("the name have already exist!\n");
  145. return;
  146. }
  147. AddPersonByName(list,tmp);
  148. }
  149. /*
  150. Function: 打印联系人列表
  151. Input: 联系人列表
  152.  
  153. */
  154. void PrintList(List list)
  155. {
  156. Position show;
  157. show=list;
  158. if(show==NULL)
  159. {
  160. return ;
  161. }
  162. printf("Now,we print the phone list:\n");
  163. while(show!=NULL)
  164. {
  165. printf("Name:%s Number:%s\n",show->name,show->number);
  166. show=show->next;
  167. }
  168.  
  169. }
  170. List FindPerson(List list)
  171. {
  172. char name[N];
  173. Position pHead=list;
  174. printf("please input the name you will find:\n");
  175. gets(name);
  176. Position node=FindPersonByName(list,name);
  177.  
  178. if(node!=NULL)
  179. printf("find success! name-> %s number-> %s\n",node->name,node->number);
  180. else
  181. printf("find failed!\n");
  182. return node;
  183. }
  184. /*
  185. Function:根据姓名删除联系人
  186. Input: 指向联系人地址的指针,联系人姓名
  187. Output: 删除成功返回1,失败返回0
  188. */
  189. int DeletePersonByName(PList list,char* name)
  190. {
  191. if(*list==NULL||name==NULL)
  192. return ;
  193. List pHead=*list;
  194. if(strcmp(pHead->name,name)==)
  195. {
  196. *list=pHead->next;
  197. free(pHead);
  198. pHead->next==NULL;
  199. return ;
  200. }
  201. List tmp=pHead->next;
  202. while(tmp!=NULL)
  203. {
  204. if(strcmp(tmp->name,name)==)
  205. {
  206. pHead->next=tmp->next;
  207. free(tmp);
  208. tmp->next=NULL;
  209. return ;
  210. }
  211. pHead=tmp;
  212. tmp=tmp->next;
  213. }
  214. return ;
  215.  
  216. }
  217. void DeletePerson(PList list)
  218. {
  219. List pHead=*list;
  220. if(pHead==NULL)
  221. {
  222. printf("there is no person you can delet\n");
  223. return ;
  224. }
  225. char name[N];
  226. printf("please input the name:\n");
  227. gets(name);
  228. DeletePersonByName(list,name);
  229. }

数据结构之链表C语言实现以及使用场景分析的更多相关文章

  1. 数据结构与算法分析——C语言描述 第三章的单链表

    数据结构与算法分析--C语言描述 第三章的单链表 很基础的东西.走一遍流程.有人说学编程最简单最笨的方法就是把书上的代码敲一遍.这个我是头文件是照抄的..c源文件自己实现. list.h typede ...

  2. C语言数据结构-单链表的实现-初始化、销毁、长度、查找、前驱、后继、插入、删除、显示操作

    1.数据结构-单链表的实现-C语言 typedef struct LNode { int data; struct LNode* next; } LNode,*LinkList; //这两者等价.Li ...

  3. 《数据结构与算法分析——C语言描述》ADT实现(NO.00) : 链表(Linked-List)

    开始学习数据结构,使用的教材是机械工业出版社的<数据结构与算法分析——C语言描述>,计划将书中的ADT用C语言实现一遍,记录于此.下面是第一个最简单的结构——链表. 链表(Linked-L ...

  4. 数据结构与算法C语言实现笔记(1)--表

    声明:此一系列博客为阅读<数据结构与算法分析--C语言描述>(Mark Allen Weiss)笔记,部分内容参考自网络:转载请注明出处. 1.表 表是最简单的数据结构,是形如A1.A2. ...

  5. 数据结构算法集---C++语言实现

    //数据结构算法集---C++语言实现 //各种类都使用模版设计,可以对各种数据类型操作(整形,字符,浮点) /////////////////////////// // // // 堆栈数据结构 s ...

  6. linux内核数据结构之链表

    linux内核数据结构之链表 1.前言 最近写代码需用到链表结构,正好公共库有关于链表的.第一眼看时,觉得有点新鲜,和我之前见到的链表结构不一样,只有前驱和后继指针,而没有数据域.后来看代码注释发现该 ...

  7. 链表c语言实现

    链表(c语言实现)--------------小练习   #include <stdio.h> #include <stdlib.h> #include <string. ...

  8. redis 系列4 数据结构之链表

    一. 概述 链表提供了高效的节点重排能力,以及顺序性的节点访问方式,并且可能通过增删节点来灵活地调整链表的长度.作为一种数据结构,在C语言中并没有内置的这种数据结构.所以Redis构建了自己的链表实现 ...

  9. 用Python实现数据结构之链表

    链表 链表与栈,队列不一样,它是由一个个节点构成的,每个节点存储着本身的一些信息,也存储着其他一个或多个节点的引用,可以从一个节点找到其他的节点,节点与节点之间就像是有链连在一起一样,这种数据结构就叫 ...

随机推荐

  1. 在linux下修改mysql的root密码

    第一种方法: root用户登录系统 /usr/local/mysql/bin/mysqladmin -u root -p password 新密码 enter password 旧密码 第二种方法: ...

  2. Linux gcc命令

    一.简介 GCC 的意思也只是 GNU C Compiler 而已.经过了这么多年的发展,GCC 已经不仅仅能支持 C 语言:它现在还支持 Ada 语言.C++ 语言.Java 语言.Objectiv ...

  3. selenium使用等待的几种方式

    1.使用java的sleep try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated c ...

  4. 【iOS 初见】第一个简单的 iOS 应用

    本实例来自 <iOS编程(第4版)>,介绍如何编写一个简单的 iOS 应用. 功能为:在视图中显示一个问题,用户点击视图下方的按钮,可以显示相应的答案,用户点击上方的按钮,则会显示一个新的 ...

  5. 2014 Super Training #4 D Paint the Grid Again --模拟

    原题:ZOJ 3780 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3780 刚开始看到还以为是搜索题,没思路就跳过了.结 ...

  6. 彻底解决Spring MVC 中文乱码 问题

    1:表单提交controller获得中文参数后乱码解决方案 注意: jsp页面编码设置为UTF-8 form表单提交方式为必须为post,get方式下面spring编码过滤器不起效果 <%@ p ...

  7. GetComponent

    GetComponent 的几种写法: 1.AutoRotation cmp1=(AutoRotation) GetComponent(typeof(AutoRotation)); 2.AutoRot ...

  8. 转:Android开发实践:用脚本编译Android工程

    转自: http://ticktick.blog.51cto.com/823160/1365947 一般情况下,我们都是使用Eclipse+ADT插件或者Android studio软件来编译Andr ...

  9. C#往线程里传递参数

    Thread (ParameterizedThreadStart) 初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托. Thread (ThreadStart) 初始化 Th ...

  10. WebResource-asp.net自定义控件引用外部资源方法

    rom:http://www.lmwlove.com/ac/ID879 在asp.net中开发自定义控件时,如果我们要用到图片,外部css,js等文件,那么最好的方式就是将这些文件作为自定义控件嵌入的 ...