用C语言完成一个链表,同时又有好多知识点需要复习
2017-04-07 09:12
465 查看
//接着写链表,想当初,大二的时候学习数据结构,那真是痛苦的要命
//现在想想,其实当时不理解没关系,后来慢慢就理解了。
//以至于后来一度以为自己不适合学计算机,加油!一起努力学习吧。
//废话不多说,今天实现的是一个“基于链表的功能”
//仍然模拟一种场景,学生姓名存储表。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>//后续使用malloc函数,需要包含此头文件
//如果编译器支持,也可以直接包含malloc.h文件
#defineOK1
#defineERROR0
typedefcharstring[20];//定义一个字符串数组类型的,长度为20;相当于charXXX[20]
structLinkNode{
stringdata;
structLinkNode*next;
};//链表,一个数据域,一个指针域。指针域指向的是本结构体
typedefstructLinkNode*LinkList;//这个熟悉吧,数据类型重定义,不懂得可以自己百度
typedefstructLinkNodeListNode;
//在此处我不禁问一下自己,能否用define定义结构体呢?
//小伙伴们知道吗?那我就再次普及一下吧:
/********************typedef和define区别**********************
**************************************************************
1、执行时间不同
#define定义的是宏定义,为可读的常量以及一些宏语句的任务
,而typedef是类型的别名,用来给类型重新起名字。typedef在编译阶段有效,由于是
在编译阶段,所以typedef有类型检查的功能。define则是宏定义,发生在预处理阶段,
编译之前,它只进行简单的字符串替换,不进行任何检查。
2、功能不同
typedef用来定义类型的别名,定义与平台无关的数据,与struct的结合使用等。
define可以为类型取别名,还可以定义常量,变量等。
3、作用域不同
define没有作用域的限制,不管在函数内,还是函数外都是从定义开始直到整个文件的结尾,
直到文件的结尾;而typedef有自己的作用域。如果定义在所有函数外,它的作用域
就是从它定义开始到文件结尾,如果放在函数内,则是从定义开始,到函数结束为位置。
相同点就是:
1、不管是typedef还是define都不能在定义之前使用!
2、typedef受函数范围的影响,而define不受
3、不管是typedef还是define,其作用域都不会扩展到别的文件,即使同一个程序的其它文件!!!
***************************************************************************************
************************完美分割线,别跑神,赶紧回来继续写链表************************/
//定义了链表的结构,下面来声明如下实现的函数:
intLink_init(LinkList*L);
//Function:初始化一个线性链表。
intLink_add(LinkListL,stringdata,intplace);
//Function:在头指针L指向的链表中,增加一个元素data,位置为place
intLink_delete(LinkListL,intplace,stringdata);
//Function:删除线性表L中,第place位置上的元素,返回给data
intLink_modify(LinkListL,intplace,stringdata);
//Function:修改线性表L中,第place位置上的元素,使其数据为data
voidLink_trival(LinkListL);
//Function:遍历一个线性表,此处并没有修改数据,所以不用传地址,也就不需要指针类型
intLink_len(LinkListL);
//Function:计算线性表的长度
intLink_empty(LinkListL);
//Funciton:判断线性表是否为空
voidLink_destroy(LinkListL);
//Function:销毁一个链表操作
LinkListLink_get_elem(LinkListL,intplace);
//Function:获取线性表L的,第place个元素的结点
//先来实现第一个函数:为什么不直接写实现,防止上下层函数之间有相互调用,所以先在此处声明
intLink_init(LinkList*L)//定义一个结构体指针的指针,因为需要修改结构体指针的指向,即结构体指针的内容
{
*L=(LinkList)malloc(sizeof(ListNode));//如果分配地址成功,则返回地址,否则为NULL
if(*L==NULL)//最好写成NULL==*L如果少写一个=不至于会报错。左边为符号常量,不能进行改变!
{
perror("failtolocatethememory!");//perror定义在stdio.h中,如果出错会输出参数+失败的原因。
returnERROR;
}
(*L)->next=NULL;
returnOK;
}
intLink_add(LinkListL,stringdata,intplace)
{
//printf("Link_add");此处不能放在第一行,否则会报错
LinkListpre,p;
intj=0;
pre=L;//L此时是头指针
while(pre->next!=NULL&&j<place-1)
{
pre=pre->next;
j++;//想要插入正确的位置,要找到插入之前的一个元素
}
if(j!=place-1)
{
printf("没有找到元素!@_@\n");
returnERROR;
}
if((p=(LinkList)malloc(sizeof(ListNode)))==NULL)
returnERROR;
strcpy(p->data,data);
//p->data=data;
p->next=pre->next;//插入操作
pre->next=p;
returnOK;
}
intLink_delete(LinkListL,intplace,stringdata)
{
LinkListpre,q;
pre=L;
if(pre->next==NULL)
{
printf("链表长度为空,无法删除");
returnERROR;
}
if(place>=Link_len(pre)+1)
{
printf("需要删除的位置比链表长度还大,不科学啊!@_@\n");
returnERROR;
}
pre=Link_get_elem(L,place-1);//获取头指针L指向的链表的元素,传给data
//data=pre->data;
strcpy(data,pre->next->data);//由于涉及字符串操作,所以要用到字符串拷贝函数
q=pre->next;//字符串的拷贝,不是简单的赋值。
pre->next=pre->next->next;
free(q);
returnOK;
}
/*特别提醒自己一下:还有一个函数memcpy(void*dest,const*src,Size_tn)
它与strcpy的区别如下:
1、复制内容不同,strcpy只能复制字符串,而后者可以复制任意内容,例如字符数组,整型,结构体等
2、复制方法不同,strcpy不需要指定长度,遇到\0才结束,所以容易溢出。后者根据给定的长度进行复制。
3、通常字符串的拷贝用前者,需要复制别的类型数据用memcpy()函数
要注意内存重叠的情况,比如以下例子:(网上找的)
chartest[]="abcdefghi";
memcpy(test+3,test,6);
如果从头到尾的复制,结果是abcabcabc,正确的结果其实应该是abcabcdef。这种情况下应该从尾向头复制。
*/
intLink_modify(LinkListL,intplace,stringdata)
{
LinkListpre;
pre=L;
if(pre==NULL)
{
printf("链表长度为空,无法修改");
returnERROR;
}
if(place>=Link_len(pre)+1)
{
printf("需要修改的位置比链表长度还大,不科学啊!@_@\n");
returnERROR;
}
pre=Link_get_elem(L,place);
//pre->data=data;//获取位置place结点指针,并对数据域修改即可
strcpy(pre->data,data);
returnOK;
}
voidLink_trival(LinkListL)
{
//在这里我要说明一下自己的错误
//我其实传进去的是头指针,那么头指针指向头结点的数据域需要访问么?
//很显然是不能访问的,因为没有意义。
/*
while(L->next!=NULL){
printf("%s",L->data);//我这样写,当然不对啦!第一个先访问的就是头结点的数据域,没有意义。
L=L->next;
*/
LinkListpre=L->next;
inttimes=0;
if(pre==NULL){
printf("线性表为空,无法遍历!");
return;
}
while(pre!=NULL)
{
printf("遍历的第%d个数据为%s\n",++times,pre->data);
pre=pre->next;
}
}
intLink_len(LinkListL)
{
intlen=0;
while(L->next!=NULL){
++len;
L=L->next;
}
returnlen;
}
intLink_empty(LinkListL)
{
if(L->next==NULL)
{
printf("Link_empty:为空@-@\n");
returnOK;//1
}
else
{
returnERROR;//0
}
}
voidLink_destroy(LinkListL)
{
LinkListpre,q;
pre=L;
while(pre!=NULL)
{
q=pre;
pre=pre->next;
free(q);
}
printf("销毁完成!");
}
LinkListLink_get_elem(LinkListL,intplace)
{
LinkListpre;
pre=L;
if(pre==NULL)
{
printf("链表长度为空,无法修改");
returnERROR;
}
if(place>=Link_len(pre)+1)
{
printf("需要修改的位置比链表长度还大,不科学啊!@_@\n");
returnERROR;
}
while(place--&&pre!=NULL){
pre=pre->next;
}
returnpre;
}
intmain(void){
//如下测试,先增加元素,遍历元素,再修改元素,遍历元素,最后删除元素
stringdata="";
LinkListL=NULL;
Link_init(&L);
Link_add(L,"小文",1);
Link_modify(L,1,"小李");
Link_trival(L);
Link_add(L,"wang",2);
Link_trival(L);
Link_delete(L,2,data);
printf("%s\n",data);
Link_trival(L);
Link_destroy(L);
/*chartest[]="abcdefghi";
memcpy(test+3,test,6);
printf("%s",test);测试结果为从尾向前复制*/
}
相关文章推荐
- 用c语言完成一个双向链表的创建,插入,删除
- 当需要2个事务才能完成一个完整业务时,回滚解决办法!抛砖引玉
- C语言实现一个简单的单向链表list
- K个有序链表共N个结点在O(NlgK)时间合并为一个新的有序链表头文件C语言
- 软件项目需要很多人一起完成可能是一个骗局
- 软件项目需要很多人一起完成可能是一个骗局
- 一个C语言中的小知识点
- hdu 3433 A Task Process N个人,第i个人完成一个A任务需要时间ai,完成一个B任务需要时间bi, 现在又X个任务A和Y个任务B,求完成所有任务所需要的最短时间。
- 通过一个简单C程序复习C语言知识
- 一个远程连接管理器,需要同时登录一批服务器的系统管理员非常好的助手。
- C语言一个双向链表的实现
- C语言实现一个简单的单向链表list
- 链表中每个结点的data域存放一个二进制位。并在此链表上实现对二进制数加1的运算。 用C语言编写 用以存放输入的二进制数 建立 一个带头结点的线性链表
- 我似乎不能成功定义一个链表。我试过 typedef struct { char *item; NODEPTR next; } *NODEPTR; 但是编译器报了错误信息。难道在C语言中一个结构不能包
- 公司这个月要同时完成好多项目!!!
- 转载的标准文档:C语言实现一个简单的单向链表list
- 用C语言编写一个包含链表的初始化、插入、删除、查找等基本操作的程序。
- 请大家看一下一个c语言中的链表问题,下面的代码是有错误的!!请大家说出错误的原因,以及修改的方法!!!
- 用C语言写一个单向链表
- 数据结构复习 之 一个简单双向链表的实现