计算机等级考试二级C语言链表复习资料
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
stud * search(stud *h,char *x) /*查找链表的函数,其中 h 指针是链表的表头指针,x 指针是 要查找的人的姓名*/ { stud *p; /*当前指针,指向要与所查找的姓名比较的结点*/ char *y; /*保存结点数据域内姓名的指针*/ p=h->link; while(p!=NULL) { y=p->name; if(strcmp(y,x)==0) /*把数据域里的姓名与所要查找的姓名比较,若相同则返回 0,即条件成立 */ return(p); /*返回与所要查找结点的地址*/ else p=p->link; } if(p==NULL) printf("没有查找到该数据!"); }
二、如何实现动态内存分配及其管理 要实现根据程序的需要动态分配存储空间,就必须用到以下几个函数 1、malloc 函数 malloc 函数的原型为: void *malloc (unsigned int size) 其作用是在内存的动态存储区中分配一个长度为 size 的连续空间。其参数是一个无符号整形数,返回值是一个 指向所分配的连续存储域的起始地址的指针。还有一点必须注意的是,当函数未能成功分配存储空间(如内存 不足)就会返回一个 NULL 指针。所以在调用该函数时应该检测返回值是否为 NULL 并执行相应的操作。 下例是一个动态分配的程序: #include #include main() { int count,*array; /*count 是一个计数器,array 是一个整型指针,也可以理解为指向一个整型数组的首地址*/ if((array(int *) malloc(10*sizeof(int)))==NULL) { printf("不能成功分配存储空间。"); exit(1); }
typedef struct node { char name[20]; struct node *link; }stud;
stud * creat(int n) /*建立链表的函数*/ { stud *p,*h,*s; int i; if((h=(stud *)malloc(sizeof(stud)))==NULL) {
typedef struct node { char name[20]; struct node *link; }stud;
stud * creat(int n) /*建立单链表的函数*/ { stud *p,*h,*s; int i; if((h=(stud *)malloc(sizeof(stud)))==NULL) { printf("不能分配内存空间!"); exit(0); } h->name[0]='\0'; h->link=NULL; p=h; for(i=0;i<N;I+Leabharlann Baidu) { if((s= (stud *) malloc(sizeof(stud)))==NULL)
p=s; } return(h); }
main() { int number; /*保存人数的变量*/ stud *head; /*head 是保存单链表的表头结点地址的指针*/ number=N; head=creat(number); /*把所新建的单链表表头地址赋给 head*/ }
这样就写好了一个可以建立包含 N 个人姓名的单链表了。 写动态内存分配的程序应注意,请尽量对分配是否成功进行检测。
三、单链表的建立 有了动态内存分配的基础,要实现链表就不难了。 所谓链表,就是用一组任意的存储单元存储线性表元素的一种数据结构。 链表又分为单链表、双向链表和循环链表等。我们先讲讲单链表。 所谓单链表,是指数据接点是单向排列的。一个单链表结点,其结构类型分为两部分: 1、数据域:用来存储本身数据 2、链域或称为指针域:用来存储下一个结点地址或者说指向其直接后继的指针。 例: typedef struct node {
2、插入(后插) 假设在一个单链表中存在 2 个连续结点 p、q(其中 p 为 q 的直接前驱),若我们需要在 p、q 之间插入一个新结点 s,那么我们必须先为 s 分配空间并赋值,然后使 p 的链域存储 s 的地址, s 的链域存储 q 的地址即可。(p->link=s;s->link=q),这样就完成了插入操作。 下例是应用插入算法的一个例子: #include #include #include #define N 10
main() {
int number; char fullname[20]; stud *head,*searchpoint; /*head 是表头指针,searchpoint 是保存符合条件的结点地址的指针 */ number=N; head=creat(number); printf("请输入你要查找的人的姓名:"); scanf("%s",fullname); searchpoint=search(head,fullname); /*调用查找函数,并把结果赋给 searchpoint 指针*/ }
四、单链表的基本运算 建立了一个单链表之后,如果要进行一些如插入、删除等操作该怎么办?所以还须掌握一些单 链表的基本算法,来实现这些操作。单链表的基本运算包括:查找、插入和删除。下面我们就 一一介绍这三种基本运算的算法,并结合我们建立单链表的例子写出相应的程序。 1、查找 对单链表进行查找的思路为:对单链表的结点依次扫描,检测其数据域是否是我们所要查好的 值,若是返回该结点的指针,否则返回 NULL。 因为在单链表的链域中包含了后继结点的存储地址,所以当我们实现的时候,只要知道该单链 表的头指针,即可依次对每个结点的数据域进行检测。 以下是应用查找算法的一个例子: #include #include #include /*包含一些字符串处理函数的头文件*/ #define N 10
计算机等级考试二级 C 语言链表复习资料 一、为什么用动态内存分配 但我们未学习链表的时候,如果要存储数量比较多的同类型或同结构的数据的时候,总是使用一个数组。比如 说我们要存储一个班级学生的某科分数,总是定义一个 float 型(存在 0.5 分)数组: float score[30]; 但是,在使用数组的时候,总有一个问题困扰着我们:数组应该有多大? 在很多的情况下,你并不能确定要使用多大的数组,比如上例,你可能并不知道该班级的学生的人数,那么你 就要把数组定义得足够大。这样,你的程序在运行时就申请了固定大小的你认为足够大的内存空间。即使你知 道该班级的学生数,但是如果因为某种特殊原因人数有增加或者减少,你又必须重新去修改程序,扩大数组的 存储范围。这种分配固定大小的内存分配方法称之为静态内存分配。但是这种内存分配的方法存在比较严重的 缺陷,特别是处理某些问题时:在大多数情况下会浪费大量的内存空间,在少数情况下,当你定义的数组不够 大时,可能引起下标越界错误,甚至导致严重后果。 那么有没有其它的方法来解决这样的外呢体呢?有,那就是动态内存分配。 所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配 不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大 小就是程序要求的大小。从以上动、静态内存分配比较可以知道动态内存分配相对于景泰内存分配的特点: 1、不需要预先分配存储空间; 2、分配的空间可以根据程序的需要扩大或缩小。
stud * creat(int n) /*建立单链表的函数,形参 n 为人数*/ { stud *p,*h,*s; /* *h 保存表头结点的指针,*p 指向当前结点的前一个结点,*s 指向当前结点 */ int i; /*计数器*/ if((h=(stud *)malloc(sizeof(stud)))==NULL) /*分配空间并检测*/ { printf("不能分配内存空间!"); exit(0); } h->name[0]='\0'; /*把表头结点的数据域置空*/ h->link=NULL; /*把表头结点的链域置空*/ p=h; /*p 指向表头结点*/ for(i=0;i<N;I++) { if((s= (stud *) malloc(sizeof(stud)))==NULL) /*分配新存储空间并检测*/ { printf("不能分配内存空间!"); exit(0); } p->link=s; /*把 s 的地址赋给 p 所指向的结点的链域,这样就把 p 和 s 所指向的结点连接起来 了*/ printf("请输入第%d 个人的姓名",i+1); scanf("%s",s->name); /*在当前结点 s 的数据域中存储姓名*/ s->link=NULL;
char name[20]; struct node *link; }stud; 这样就定义了一个单链表的结构,其中 char name[20]是一个用来存储姓名的字符型数组,指 针*link 是一个用来存储其直接后继的指针。 定义好了链表的结构之后,只要在程序运行的时候爱数据域中存储适当的数据,如有后继结点, 则把链域指向其直接后继,若没有,则置为 NULL。 下面就来看一个建立带表头(若未说明,以下所指链表均带表头)的单链表的完整程序。 #include #include /*包含动态内存分配函数的头文件*/ #define N 10 /*N 为人数*/ typedef struct node { char name[20]; struct node *link; }stud;
printf("不能分配内存空间!"); exit(0); } h->name[0]='\0'; h->link=NULL; p=h; for(i=0;i<N;I++) { if((s= (stud *) malloc(sizeof(stud)))==NULL) { printf("不能分配内存空间!"); exit(0); } p->link=s; printf("请输入第%d 个人的姓名",i+1); scanf("%s",s->name); s->link=NULL; p=s; } return(h); }
for (count=0;count〈10;count++) /*给数组赋值*/ array[count]=count; for(count=0;count〈10;count++) /*打印数组元素*/ printf("-",array[count]); } 上例中动态分配了 10 个整型存储区域,然后进行赋值并打印。例中 if((array(int *) malloc(10*sizeof(int)))==NUL L)语句可以分为以下几步: 1)分配 10 个整型的连续存储空间,并返回一个指向其起始地址的整型指针 2)把此整型指针地址赋给 array 3)检测返回值是否为 NULL 2、free 函数 由于内存区域总是有限的,不能不限制地分配下去,而且一个程序要尽量节省资源,所以当所分配的内存区域 不用时,就要释放它,以便其它的变量或者程序使用。这时我们就要用到 free 函数。 其函数原型是: void free(void *p) 作用是释放指针 p 所指向的内存区。 其参数 p 必须是先前调用 malloc 函数或 calloc 函数(另一个动态分配存储区域的函数)时返回的指针。给 free 函数传递其它的值很可能造成死机或其它灾难性的后果。 注意:这里重要的是指针的值,而不是用来申请动态内存的指针本身。例: int *p1,*p2; p1=malloc(10*sizeof(int)); p2=p1; …… free(p2) /*或者 free(p2)*/ malloc 返回值赋给 p1,又把 p1 的值赋给 p2,所以此时 p1,p2 都可作为 free 函数的参数。 malloc 函数是对存储区域进行分配的。 free 函数是释放已经不用的内存区域的。 所以由这两个函数就可以实现对内存区域进行动态分配并进行简单的管理了。
二、如何实现动态内存分配及其管理 要实现根据程序的需要动态分配存储空间,就必须用到以下几个函数 1、malloc 函数 malloc 函数的原型为: void *malloc (unsigned int size) 其作用是在内存的动态存储区中分配一个长度为 size 的连续空间。其参数是一个无符号整形数,返回值是一个 指向所分配的连续存储域的起始地址的指针。还有一点必须注意的是,当函数未能成功分配存储空间(如内存 不足)就会返回一个 NULL 指针。所以在调用该函数时应该检测返回值是否为 NULL 并执行相应的操作。 下例是一个动态分配的程序: #include #include main() { int count,*array; /*count 是一个计数器,array 是一个整型指针,也可以理解为指向一个整型数组的首地址*/ if((array(int *) malloc(10*sizeof(int)))==NULL) { printf("不能成功分配存储空间。"); exit(1); }
typedef struct node { char name[20]; struct node *link; }stud;
stud * creat(int n) /*建立链表的函数*/ { stud *p,*h,*s; int i; if((h=(stud *)malloc(sizeof(stud)))==NULL) {
typedef struct node { char name[20]; struct node *link; }stud;
stud * creat(int n) /*建立单链表的函数*/ { stud *p,*h,*s; int i; if((h=(stud *)malloc(sizeof(stud)))==NULL) { printf("不能分配内存空间!"); exit(0); } h->name[0]='\0'; h->link=NULL; p=h; for(i=0;i<N;I+Leabharlann Baidu) { if((s= (stud *) malloc(sizeof(stud)))==NULL)
p=s; } return(h); }
main() { int number; /*保存人数的变量*/ stud *head; /*head 是保存单链表的表头结点地址的指针*/ number=N; head=creat(number); /*把所新建的单链表表头地址赋给 head*/ }
这样就写好了一个可以建立包含 N 个人姓名的单链表了。 写动态内存分配的程序应注意,请尽量对分配是否成功进行检测。
三、单链表的建立 有了动态内存分配的基础,要实现链表就不难了。 所谓链表,就是用一组任意的存储单元存储线性表元素的一种数据结构。 链表又分为单链表、双向链表和循环链表等。我们先讲讲单链表。 所谓单链表,是指数据接点是单向排列的。一个单链表结点,其结构类型分为两部分: 1、数据域:用来存储本身数据 2、链域或称为指针域:用来存储下一个结点地址或者说指向其直接后继的指针。 例: typedef struct node {
2、插入(后插) 假设在一个单链表中存在 2 个连续结点 p、q(其中 p 为 q 的直接前驱),若我们需要在 p、q 之间插入一个新结点 s,那么我们必须先为 s 分配空间并赋值,然后使 p 的链域存储 s 的地址, s 的链域存储 q 的地址即可。(p->link=s;s->link=q),这样就完成了插入操作。 下例是应用插入算法的一个例子: #include #include #include #define N 10
main() {
int number; char fullname[20]; stud *head,*searchpoint; /*head 是表头指针,searchpoint 是保存符合条件的结点地址的指针 */ number=N; head=creat(number); printf("请输入你要查找的人的姓名:"); scanf("%s",fullname); searchpoint=search(head,fullname); /*调用查找函数,并把结果赋给 searchpoint 指针*/ }
四、单链表的基本运算 建立了一个单链表之后,如果要进行一些如插入、删除等操作该怎么办?所以还须掌握一些单 链表的基本算法,来实现这些操作。单链表的基本运算包括:查找、插入和删除。下面我们就 一一介绍这三种基本运算的算法,并结合我们建立单链表的例子写出相应的程序。 1、查找 对单链表进行查找的思路为:对单链表的结点依次扫描,检测其数据域是否是我们所要查好的 值,若是返回该结点的指针,否则返回 NULL。 因为在单链表的链域中包含了后继结点的存储地址,所以当我们实现的时候,只要知道该单链 表的头指针,即可依次对每个结点的数据域进行检测。 以下是应用查找算法的一个例子: #include #include #include /*包含一些字符串处理函数的头文件*/ #define N 10
计算机等级考试二级 C 语言链表复习资料 一、为什么用动态内存分配 但我们未学习链表的时候,如果要存储数量比较多的同类型或同结构的数据的时候,总是使用一个数组。比如 说我们要存储一个班级学生的某科分数,总是定义一个 float 型(存在 0.5 分)数组: float score[30]; 但是,在使用数组的时候,总有一个问题困扰着我们:数组应该有多大? 在很多的情况下,你并不能确定要使用多大的数组,比如上例,你可能并不知道该班级的学生的人数,那么你 就要把数组定义得足够大。这样,你的程序在运行时就申请了固定大小的你认为足够大的内存空间。即使你知 道该班级的学生数,但是如果因为某种特殊原因人数有增加或者减少,你又必须重新去修改程序,扩大数组的 存储范围。这种分配固定大小的内存分配方法称之为静态内存分配。但是这种内存分配的方法存在比较严重的 缺陷,特别是处理某些问题时:在大多数情况下会浪费大量的内存空间,在少数情况下,当你定义的数组不够 大时,可能引起下标越界错误,甚至导致严重后果。 那么有没有其它的方法来解决这样的外呢体呢?有,那就是动态内存分配。 所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配 不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大 小就是程序要求的大小。从以上动、静态内存分配比较可以知道动态内存分配相对于景泰内存分配的特点: 1、不需要预先分配存储空间; 2、分配的空间可以根据程序的需要扩大或缩小。
stud * creat(int n) /*建立单链表的函数,形参 n 为人数*/ { stud *p,*h,*s; /* *h 保存表头结点的指针,*p 指向当前结点的前一个结点,*s 指向当前结点 */ int i; /*计数器*/ if((h=(stud *)malloc(sizeof(stud)))==NULL) /*分配空间并检测*/ { printf("不能分配内存空间!"); exit(0); } h->name[0]='\0'; /*把表头结点的数据域置空*/ h->link=NULL; /*把表头结点的链域置空*/ p=h; /*p 指向表头结点*/ for(i=0;i<N;I++) { if((s= (stud *) malloc(sizeof(stud)))==NULL) /*分配新存储空间并检测*/ { printf("不能分配内存空间!"); exit(0); } p->link=s; /*把 s 的地址赋给 p 所指向的结点的链域,这样就把 p 和 s 所指向的结点连接起来 了*/ printf("请输入第%d 个人的姓名",i+1); scanf("%s",s->name); /*在当前结点 s 的数据域中存储姓名*/ s->link=NULL;
char name[20]; struct node *link; }stud; 这样就定义了一个单链表的结构,其中 char name[20]是一个用来存储姓名的字符型数组,指 针*link 是一个用来存储其直接后继的指针。 定义好了链表的结构之后,只要在程序运行的时候爱数据域中存储适当的数据,如有后继结点, 则把链域指向其直接后继,若没有,则置为 NULL。 下面就来看一个建立带表头(若未说明,以下所指链表均带表头)的单链表的完整程序。 #include #include /*包含动态内存分配函数的头文件*/ #define N 10 /*N 为人数*/ typedef struct node { char name[20]; struct node *link; }stud;
printf("不能分配内存空间!"); exit(0); } h->name[0]='\0'; h->link=NULL; p=h; for(i=0;i<N;I++) { if((s= (stud *) malloc(sizeof(stud)))==NULL) { printf("不能分配内存空间!"); exit(0); } p->link=s; printf("请输入第%d 个人的姓名",i+1); scanf("%s",s->name); s->link=NULL; p=s; } return(h); }
for (count=0;count〈10;count++) /*给数组赋值*/ array[count]=count; for(count=0;count〈10;count++) /*打印数组元素*/ printf("-",array[count]); } 上例中动态分配了 10 个整型存储区域,然后进行赋值并打印。例中 if((array(int *) malloc(10*sizeof(int)))==NUL L)语句可以分为以下几步: 1)分配 10 个整型的连续存储空间,并返回一个指向其起始地址的整型指针 2)把此整型指针地址赋给 array 3)检测返回值是否为 NULL 2、free 函数 由于内存区域总是有限的,不能不限制地分配下去,而且一个程序要尽量节省资源,所以当所分配的内存区域 不用时,就要释放它,以便其它的变量或者程序使用。这时我们就要用到 free 函数。 其函数原型是: void free(void *p) 作用是释放指针 p 所指向的内存区。 其参数 p 必须是先前调用 malloc 函数或 calloc 函数(另一个动态分配存储区域的函数)时返回的指针。给 free 函数传递其它的值很可能造成死机或其它灾难性的后果。 注意:这里重要的是指针的值,而不是用来申请动态内存的指针本身。例: int *p1,*p2; p1=malloc(10*sizeof(int)); p2=p1; …… free(p2) /*或者 free(p2)*/ malloc 返回值赋给 p1,又把 p1 的值赋给 p2,所以此时 p1,p2 都可作为 free 函数的参数。 malloc 函数是对存储区域进行分配的。 free 函数是释放已经不用的内存区域的。 所以由这两个函数就可以实现对内存区域进行动态分配并进行简单的管理了。