牢骚:本篇博客两个星期前已经存为草稿,鉴于发生一些糟糕的事情,今天才基本完成。本人6月份应届毕业生一枚,毕业后当天来到帝都,以后也很是顺利,面试了俩家公司都成功了。一家作C++方面电商ERP,一家作wifi模块,以为第二家公司小,薪资低,可是以为好玩就去了。同时,在学校也喝了很多鸡汤,以为公司小怎么了。然而去了不到20天,公司被深圳一家公司收购了,公司动员我去深圳,我尼玛我才来20多天啊,有木有?并且感受公司作这么大的决定都是随时拍板的吗?node
本来觉得一个公司的生命力强到能够忽略的几率,然而当本身真实的遇到这一切,才知道这个社会有多残忍,公司的生存可能比一个员工的生存更要困难。linux
接下来就是找工做了,跑呀,找呀。。。。。。。。 一路被忽略,一路被放鸽子,一路被无视。。。。。。。 内心五味杂陈。。。。。。。。。程序员
so,可能我仍是太菜了,这种玩计算机的心态,也许会被生活玩,惟有认真拼命的学习也许可以拯救个人颓势。面试
感谢seven,严厉也好,鼓励也好,短短的一个月,您教会了我许多,感谢您的知遇之恩!愿大家去深圳一切顺利!待倔强的我在北京玩上一阵!算法
————————————————————————————————————————————————————————————————————————————————数组
链表是数据结构中比较基础也是比较重要的类型之一,那么有了数组,为何咱们还须要链表呢!或者说设计链表这种数据结构的初衷在哪里?服务器
这是由于,在咱们使用数组的时候,须要预先设定目标群体的个数,也即数组容量的大小,然而实时状况下咱们目标的个数咱们是不肯定的,所以咱们老是要把数组的容量设置的很大,这样以来就浪费了不少的空间。另外,数组在进行插入操做和删除操做的时候,在插入或者删除制定元素以后,咱们每每须要进行循环移位,这增长了咱们的线性开销。数据结构
正是因为以上的两种主要缘由,链表被设计出来用于通常表的操做。为了不上面描述数组的两种弊端,咱们但愿链表有一下的特色less
1 能够灵活的扩展本身的长度。函数
2 存储地址不连续,删除或者插入操做的时候不须要循环移位。
要实现以上两个特色,咱们需既要保证每一个节点的独立性,又要保存相邻两个节点的联系。
为此,链表通常被设计为下面的形式。
Node--->Node---->Node
链表是由一个一个的节点组成的,能够方便和自由的插入未知个Node,前一个节点中用指针保存着下一个节点的位置,这样以来便顺利的完成了咱们对链表的两点指望,可是惟一的缺点是增长了额外的空间消耗。
————————————————————————————————————————————————————————————————————————————
链表的定义:
链表的定义通常使用结构体,在看《数据结构与算法分析》这本书的时候发现,书中频繁的使用typedef的关键字,结果然的很棒不只保持的代码的整洁程度,也让咱们在下面的编码过程当中少见了不少烦人的指针(固然指针仍是一直存在的)。因此这里也借用了书中的定义方法。
struct Node; typedef struct Node* PtrNode; typedef PtrNode Position; typedef PtrNode List; struct Node{ int Value; PtrNode Next; };
下面接着书写一个创建链表的函数,输入每一个节点的值,直到这个值是-1的时候函数结束。
在这个里面,我之前一直搞不明白为何须要定义三个Node *,如今终于了解了,最终仍是复习了指针的内容明白的,这里说一下指针实现链表对指针的操做很频繁,须要比较扎实的掌握了指针以后,在来看链表会轻松不少。在下面的一段程序里,我分别定义了head/p/tmp这三个指向节点结构体的指针,head的主要做用就像一个传销头目,他会主动联系上一个下线p,而后他就什么也不干了,p接着去发展一个又一个的下线tmp,结果一串以head为首的链表就出来了。
起先,我总以为有了head,为何还要p,这是由于若是直接使用head去指向下一个节点,head的位置也是不断在移动的,即它永远处于链表的尾端,这样当咱们返回链表的时候,实际上是空值。因此,咱们须要p这个中转环节。(其实,这种作法在指针中很是广泛,大部分有返回指针类型的函数中,都会首先定义一个指针变量来保存函数的传入的参数,而不是对参数直接进行操做)。
/* 函数功能:建立一个链表 函数描述:每次输入一个新的整数,即把新增长一个节点存放该整数, 当输入的整数为-1时,函数结束。 */ List create() { int n=0; Position p,head,tmp; head=NULL; tmp=malloc(sizeof(struct Node)); if(tmp==NULL) { printf("tmp malloc failed!\n"); return NULL; } else { p=tmp; printf("please input the first node's message!\n"); scanf("%d",&(tmp->Value)); } while(tmp->Value!=-1) { n+=1; if(n==1) { head=p; tmp->Next=NULL; } else { p->Next=tmp; } p=tmp; tmp=malloc(sizeof(struct Node)); printf("please input the %d node!\n",n+1); scanf("%d",&(tmp->Value)); } p->Next=NULL; free(tmp); //free函数free掉的只是申请的空间,可是指针仍是依然存在的。 tmp=NULL; return head; }
接下来,在写一个删除链表节点的函数,输入一个整数而后遍历链表节点,当链表节点的值与该整数相等的时候,即把该节点删除。
在完成这个函数首先必定要把这个过程思考清楚,不能否认我以前是一个上来就敲代码的人,看了《剑指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便可。
只要完成上面的分析以及考虑到各类状况,咱们完成下面的代码就水到渠成了。
/* 函数功能:删除链表中指定值的节点(若是存在多个,只删除第一个) 本例中输入一个整数,删除链表节点值为这个整数的节点。 */ List DeleteNode(List list) { Position p,tmp; int value; if(list==NULL) { printf("The list is null,function return!\n"); return NULL; } else { printf("please input the delete Node's value:\n"); scanf("%d",&value); } p=list; if(p->Value==value) { list=p->Next; free(p); p=NULL; return list; } while(p!=NULL&&p->Value!=value) { tmp=p; p=p->Next; } if(p->Value==value) { if(p->Next!=NULL){ tmp->Next=p->Next; } else { tmp->Next=NULL; } free(p); p=NULL; } return list; }
关于链表的使用场景分析:
链表在程序开发中用到的频率仍是很是高的,因此在高级语言中每每会对链表进行一些实现,好比STL中list以及Java中也有相似的东西。在目前的服务器端开发,主要运用链表来接收一些从数据中取出来的数据进行处理。
即便你不知道链表的底层实现,仍然能够成功的运用STL里面的现成的东西。可是做为一个学习者,我以为会使用和从底层掌握仍然是两个不一样的概念,linux之父说:“talk is less,show you code”。
如下的程序,用链表模拟了一个电话通信录的功能,包括添加联系人,查找联系人,以及删除联系人。
PS:关于鲁棒性,程序中最大的危险是使用了gets这个函数,目前先保留使用gets,等待找到工做以后在作进一步的程序完善。
/************************************************************************** Programe: This is a phone list write by list The programe is just prictise for list Author: heat nan Mail:964465194@qq.com Data:2015/07/27 **************************************************************************/ #include<stdio.h> #include<string.h> #include<stdlib.h> #define N 25 #define M 15 struct node; typedef struct node* p_node; typedef p_node List; typedef p_node Position; typedef struct node** PList; struct node{ char name[N]; char number[M]; Position next; }; int JudgeNameExist(List list,char* name); void AddPerson(PList list); void PrintList(List list); List FindPerson(List list); List FindPersonByName(List list,char* name); int AddPersonByName(PList list,List node); int DeletePersonByName(PList list,char* name); void DeletePerson(PList list); int main() { List list=NULL; Position p; char cmd[100]; while(1) { printf(" MAIN \n"); printf(" ******* 1 add a person *******\n"); printf(" ******* 2 show the phone list *******\n"); printf(" ******* 3 find from phone list *******\n"); printf(" ******* 4 delete from phone list *******\n\n\n"); printf("Please input the cmd number:\n"); gets(cmd); switch(cmd[0]) { case '1': AddPerson(&list); break; case '2': PrintList(list); break; case '3': FindPerson(list); break; case '4': DeletePerson(&list); break; default: printf("wrong cmd!\n"); break; } } return 0; } /* Function:判断要添加的联系人名称是否已经存在于电话簿中. Input: List 电话列表,name 要添加的联系人的姓名. Return: 已经存在返回1,不存在返回0. */ int JudgeNameExist(List list,char* name) { if(FindPersonByName(list,name)!=NULL) return 1; else return 0; } /* Function:根据输入的姓名查找联系人的信息节点 Input: 要输入的电话列表list,姓名name Return: 返回查找到的节点 */ List FindPersonByName(List list,char* name) { while(list!=NULL) { if(strcmp(list->name,name)==0) break; list=list->next; } return list; } /* Function:根据姓名添加新的联系人到联系人列表 Input: 指向联系人列表地址的指针, 新用户节点 Return: 添加成功返回1,添加失败返回0 */ int AddPersonByName(PList list,List node) { if(node==NULL) { printf("the node is NULL!\n"); return 0; } if(*list==NULL) { *list=node; return 1; } List pHead=*list; while(pHead->next!=NULL) pHead=pHead->next; pHead->next=node; return 1; } void AddPerson(PList list) { Position tmp; Position p_head; tmp=(struct node*)malloc(sizeof(struct node)); char name[N]; char number[M]; if(tmp==NULL) { printf("malloc the tmp node failed in function add person!\n"); } else { printf("please input the name:\n"); gets(name); printf("please input the number:\n"); gets(number); strcpy(tmp->name,name); strcpy(tmp->number,number); tmp->next=NULL; } if(JudgeNameExist(*list,name)==1) { free(tmp); printf("the name have already exist!\n"); return; } AddPersonByName(list,tmp); } /* Function: 打印联系人列表 Input: 联系人列表 */ void PrintList(List list) { Position show; show=list; if(show==NULL) { return ; } printf("Now,we print the phone list:\n"); while(show!=NULL) { printf("Name:%s Number:%s\n",show->name,show->number); show=show->next; } } List FindPerson(List list) { char name[N]; Position pHead=list; printf("please input the name you will find:\n"); gets(name); Position node=FindPersonByName(list,name); if(node!=NULL) printf("find success! name-> %s number-> %s\n",node->name,node->number); else printf("find failed!\n"); return node; } /* Function:根据姓名删除联系人 Input: 指向联系人地址的指针,联系人姓名 Output: 删除成功返回1,失败返回0 */ int DeletePersonByName(PList list,char* name) { if(*list==NULL||name==NULL) return 0; List pHead=*list; if(strcmp(pHead->name,name)==0) { *list=pHead->next; free(pHead); pHead->next==NULL; return 0; } List tmp=pHead->next; while(tmp!=NULL) { if(strcmp(tmp->name,name)==0) { pHead->next=tmp->next; free(tmp); tmp->next=NULL; return 1; } pHead=tmp; tmp=tmp->next; } return 0; } void DeletePerson(PList list) { List pHead=*list; if(pHead==NULL) { printf("there is no person you can delet\n"); return ; } char name[N]; printf("please input the name:\n"); gets(name); DeletePersonByName(list,name); }