1、实验3 带头节点的单链表
运行环境:Dev-C++
一、实验目的
1.理解带头节点的单链表的特点,掌握其基本操作。
2.熟练掌握运用带头节点链表表示特定形式的数据的方法,并设计出有关算法。
二、实验内容
已知带头节点的链表结构定义及头插法建表,尾插法建表和打印链表等函数定义如下(详见slnklist.h文件),基于该内容完成实验题1~实验9。
#include <stdio.h> #include <stdlib.h> /**************************************/ /* 链表实现的头文件,文件名slnklist.h */ /**************************************/ typedef int datatype; typedef struct link_node{ datatype info; struct link_node *next; }node; typedef node *linklist; /******************************************/ /*函数名称:creatbystack() */ /*函数功能:头插法建立带头结点的单链表 */ /******************************************/ linklist creatbystack() { linklist head,s; datatype x; head=(linklist)malloc(sizeof(node)); head->next=NULL; printf("请输入整数序列(空格分开,以0结束):\n"); scanf("%d",&x); while (x!=0) { s=(linklist)malloc(sizeof(node)); s->info=x; s->next=head->next; head->next=s; scanf("%d",&x); } return head; } /***************************************/ /*函数名称:creatbyqueue() */ /*函数功能:尾插法建立带头结点的单链表 */ /***************************************/ linklist creatbyqueue() { linklist head,r,s; datatype x; head=r=(linklist)malloc(sizeof(node)); head->next=NULL; printf("请输入整数序列(空格分开,以0结束):\n"); scanf("%d",&x); while (x!=0) { s=(linklist)malloc(sizeof(node)); s->info=x; r->next=s; r=s; scanf("%d",&x); } r->next=NULL; return head; } /**********************************/ /*函数名称:print() */ /*函数功能:输出带头结点的单链表 */ /**********************************/ void print(linklist head) { linklist p; int i=0; p=head->next; printf("List is:\n"); while(p) { printf("%7d",p->info); i++; if (i%10==0) printf("\n"); p=p->next; } printf("\n"); } /******************************************/ /*函数名称:creatLink() */ /*函数功能:从文件中读入n个数据构成单链表 */ /******************************************/ linklist creatLink(char *f, int n) { FILE *fp; int i; linklist s,head,r; head=r=(linklist)malloc(sizeof(node)); head->next=NULL; fp=fopen(f,"r"); if (fp==NULL) return head; else { for (i=0;i<n;i++) { s=(linklist)malloc(sizeof(node)); fscanf(fp,"%d",&(s->info)); r->next=s; r=s; } r->next=NULL; fclose(fp); return head; } } /* 函数名称:writetofile 函数功能:将链表内容存入文件f */ void writetofile(linklist head, char *f) { FILE *fp; linklist p; int i=0; fp=fopen(f,"w"); if (fp!=NULL) { p=head->next; fprintf(fp,"%s","List is:\n"); while(p) { fprintf(fp,"%7d",p->info); i++; if (i%10==0) fprintf(fp,"%c",'\n'); p=p->next; } fprintf(fp,"%c",'\n'); fclose(fp); } else printf("创建文件失败!"); } /**********************************/ /*函数名称:delList() */ /*函数功能:释放带头结点的单链表 */ /**********************************/ void delList(linklist head) { linklist p=head; while (p) { head=p->next; free(p); p=head; } }
实验3.1
编写函数void delx(linklist head, datatype x),删除带头结点单链表head中第一个值为x 的结点。 并构造测试用例进行测试。
/*编写函数void delx(linklist head, datatype x),删除带头结点单链表head中第一个值为x 的结点。 并构造测试用例进行测试。 */ /**********************************/ /*文件名称:lab3_01.c */ /**********************************/ #include "slnklist.h" /*请将本函数补充完整,并进行测试*/ linklist delx(linklist head,datatype x) { node* p=head; node* q=p->next; while(q){ if(q->info==x){ p->next=q->next; return head; break; } p=p->next; q=q->next; } } int main() { datatype x; linklist head; head=creatbyqueue(); /*尾插入法建立带头结点的单链表*/ print(head); printf("请输入要删除的值:"); scanf("%d",&x); head=delx(head,x); /*删除单链表的第一个值为x的结点*/ print(head); delList(head); /*释放单链表空间*/ return 0; }
实验3.2
假设线性表(a1,a2,a3,…an)采用带头结点的单链表存储,请设计算法函数linklist reverse(linklist head), 将带头结点的单链表head就地倒置,使表变成(an,an-1,…a3.a2,a1)。并构造测试用例进行测试。
/**********************************/ /*文件名称:lab3_02.c */ /**********************************/ /* 假设线性表(a1,a2,a3,…an)采用带头结点的单链表存储,请设计算法函数linklist reverse(linklist head), 将带头结点的单链表head就地倒置,使表变成(an,an-1,…a3.a2,a1)。并构造测试用例进行测试。 */ #include "slnklist.h" #include<iostream> using namespace std; #include<vector> /*请将本函数补充完整,并进行测试*/ linklist reverse(linklist head) { vector<int> a; node* p=head->next; while(p){ a.push_back(p->info); p=p->next; } p=head->next; while(p){ p->info=a.back(); a.pop_back(); p=p->next; } return head; } int main() { datatype x; linklist head; head=creatbystack(); /*头插入法建立带头结点的单链表*/ print(head); /*输出原链表*/ head= reverse(head); /*倒置单链表*/ print(head); /*输出倒置后的链表*/ delList(head); return 0; }
实验3.3
假设带头结点的单链表head是升序排列的,设计算法函数linklist insert(linklist head,datatype x), 将值为x的结点插入到链表head中,并保持链表有序性。 分别构造插入到表头、表中和表尾三种情况的测试用例进行测试。
/* 假设带头结点的单链表head是升序排列的,设计算法函数linklist insert(linklist head,datatype x), 将值为x的结点插入到链表head中,并保持链表有序性。 分别构造插入到表头、表中和表尾三种情况的测试用例进行测试。 */ /**********************************/ /*文件名称:lab3_03.c */ /**********************************/ #include "slnklist.h" /*请将本函数补充完整,并进行测试*/ linklist insert(linklist head ,datatype x) { node* p=head; node* q=p->next; while(q){ if(q->info>x){ node* a=(node*)malloc(sizeof(node)); p->next=a; a->info=x; a->next=q; return head; } else{ p=p->next; q=q->next; } } if(q==NULL){ node* a=(node*)malloc(sizeof(node)); p->next=a; a->info=x; a->next=NULL; return head; } } int main() { datatype x; linklist head; printf("输入一组升序排列的整数:\n"); head=creatbyqueue(); /*尾插入法建立带头结点的单链表*/ print(head); printf("请输入要插入的值:"); scanf("%d",&x); head=insert(head,x); /*将输入的值插入到带头结点的单链表适当位置*/ print(head); delList(head); return 0; }
实验3.4
编写算法函数linklist delallx(linklist head, int x),删除带头结点单链表head中所有值为x的结点。
/* 编写算法函数linklist delallx(linklist head, int x),删除带头结点单链表head中所有值为x的结点。 */ /**********************************/ /*文件名称:lab3_04.c */ /**********************************/ #include "slnklist.h" /*请将本函数补充完整,并进行测试*/ linklist delallx(linklist head,int x) { node* p=head; node* q=head->next; while(q){ if(q->info==x){ p->next=q->next; q=q->next; } else{ q=q->next; p=p->next; } } return head; } int main() { datatype x; linklist head; head=creatbyqueue(); /*尾插入法建立带头结点的单链表*/ print(head); printf("请输入要删除的值:"); scanf("%d",&x); head=delallx(head,x); print(head); delList(head); return 0; }
实验3.5
已知线性表存储在带头结点的单链表head中,请设计算法函数void sort(linklist head),将head中的结点按结点值升序排列。
/* 已知线性表存储在带头结点的单链表head中,请设计算法函数void sort(linklist head),将head中的结点按结点值升序排列。 */ /**********************************/ /*文件名称:lab3_05.c */ /**********************************/ #include "slnklist.h" #include<vector> #include<iostream> using namespace std; /*请将本函数补充完整,并进行测试*/ void sort(linklist head){ vector<int> a; node* pp=head->next; while(pp){ a.push_back(pp->info); pp=pp->next; } head->next=NULL; while(!a.empty()){ node* pp=head; node* q=head->next; while(q){ if(q->info>a.back()){ node* s=(node*)malloc(sizeof(node)); pp->next=s; s->info=a.back(); s->next=q; a.pop_back(); break; } else{ pp=q; q=q->next; } } if(!q){ node* s=(node*)malloc(sizeof(node)); pp->next=s; s->next=NULL; s->info=a.back(); a.pop_back(); } } } int main() { linklist head; head=creatbyqueue(); /*尾插法建立带头结点的单链表*/ print(head); /*输出单链表head*/ sort(head); /*排序*/ print(head); delList(head); return 0; }
实验3.6
已知两个带头结点的单链表L1和L2中的结点值均已按升序排序,设计算法函数 linklist mergeAscend (linklist L1,linklist L2)将L1和L2合并成一个升序的 带头结单链表作为函数的返回结果; 设计算法函数linklist mergeDescend (linklist L1,linklist L2) 将L1和L2合并成一个降序的带头结单链表作为函数的返回结果; 并设计main()函数进行测试。
/* 已知两个带头结点的单链表L1和L2中的结点值均已按升序排序,设计算法函数 linklist mergeAscend (linklist L1,linklist L2)将L1和L2合并成一个升序的 带头结单链表作为函数的返回结果; 设计算法函数linklist mergeDescend (linklist L1,linklist L2) 将L1和L2合并成一个降序的带头结单链表作为函数的返回结果; 并设计main()函数进行测试。 */ /**********************************/ /*文件名称:lab3_06.c */ /**********************************/ #include "slnklist.h" /*请将本函数补充完整,并进行测试*/ linklist mergeAscend(linklist L1,linklist L2) { node* L3=(node*)malloc(sizeof(node)); node* r=L3; node* p=L1->next,*q=L2->next; while(p&&q){ if(p->info>q->info){ node* s=(node*)malloc(sizeof(node)); s->info=q->info; q=q->next; r->next=s; r=s; } else{ node* s=(node*)malloc(sizeof(node)); s->info=p->info; p=p->next; r->next=s; r=s; } } while(p){ node* s=(node*)malloc(sizeof(node)); s->info=p->info; p=p->next; r->next=s; r=s; } while(q){ node* s=(node*)malloc(sizeof(node)); s->info=q->info; q=q->next; r->next=s; r=s; } r->next=NULL; return L3; } linklist mergeDescend(linklist L1,linklist L2) { node* r=NULL; node* L3=(node*)malloc(sizeof(node)); node* p=L1->next,*q=L2->next; while(p&&q){ if(p->info>q->info){ node* s=(node*)malloc(sizeof(node)); s->info=q->info; q=q->next; s->next=r; r=s; } else{ node* s=(node*)malloc(sizeof(node)); s->info=p->info; p=p->next; s->next=r; r=s; } } while(p){ node* s=(node*)malloc(sizeof(node)); s->info=p->info; p=p->next; s->next=r; r=s; } while(q){ node* s=(node*)malloc(sizeof(node)); s->info=q->info; q=q->next; s->next=r; r=s; } L3->next=r; return L3; } int main() { linklist h1,h2,h3; h1=creatbyqueue(); /*尾插法建立单链表,请输入升序序列*/ h2=creatbyqueue(); print(h1); print(h2); // h3=mergeAscend(h1,h2);/*升序合并到h3*/ h3=mergeDescend(h1,h2); //降序合并请调用 print(h3); delList(h3); return 0; }
实验3.7
设计一个算法linklist interSection(linklist L1,linklist L2), 求两个单链表表示的集合L1和L2的交集,并将结果用一个新的带头 结点的单链表保存并返回表头地址。
/* 设计一个算法linklist interSection(linklist L1,linklist L2), 求两个单链表表示的集合L1和L2的交集,并将结果用一个新的带头 结点的单链表保存并返回表头地址。 */ /**********************************/ /*文件名称:lab3_07.c */ /**********************************/ #include "slnklist.h" /*请将本函数补充完整,并进行测试*/ linklist interSection(linklist L1, linklist L2) { node* L3=(node*)malloc(sizeof(node)); node* r=L3; node* p=L1->next; while(p){ node* q=L2->next; while(q){ if(p->info==q->info){ node* s=(node*)malloc(sizeof(node)); s->info=p->info; r->next=s; r=s; r->next=NULL; } q=q->next; } p=p->next; } return L3; } int main() { linklist h1,h2,h3; h1=creatbyqueue(); /*尾插法建立单链表,输入时请勿输入重复数据*/ h2=creatbyqueue(); print(h1); /*输出单链表h1*/ print(h2); h3=interSection(h1,h2); /* 求h1和h2的交集*/ print(h3); delList(h1); delList(h2); delList(h3); return 0; }
实验3.8
请编写一个算法函数void partion(linklist head), 将带头结点的单链表head中的所有值为奇数的结点调整 到链表的前面,所有值为偶数的结点调整到链表的后面。
/* 请编写一个算法函数void partion(linklist head), 将带头结点的单链表head中的所有值为奇数的结点调整 到链表的前面,所有值为偶数的结点调整到链表的后面。 */ /**********************************/ /*文件名称:lab3_08.c */ /**********************************/ #include "slnklist.h" /*请将本函数补充完整,并进行测试*/ void partion(linklist head) { if(head->next->next&&head->next){ node* p=head->next; node* q=head->next->next; while(q){ if(q->info%2==1){ p->next=p->next->next; q->next=head->next; head->next=q; q=p->next; } else{ p=p->next; q=q->next; } } } } int main() { linklist head; head=creatbyqueue(); /*尾插法建立带头结点的单链表*/ print(head); /*输出单链表head*/ partion(head); print(head); delList(head); return 0; }
实验3.9
编写一个程序,用尽可能快的方法返回带头结点单链表中倒数第k个结点的地址,如果不存在,则返回NULL。
/* 编写一个程序,用尽可能快的方法返回带头结点单链表中倒数第k个结点的地址,如果不存在,则返回NULL。 */ /**********************************/ /*文件名称:lab3_09.c */ /**********************************/ #include "slnklist.h" /*请将本函数补充完整,并进行测试*/ linklist search(linklist head,int k) { int i=0; node* p=head; while(p){ i++; p=p->next; } p=head; if(i-k<=0) return NULL; else{ for(int j=0;j<i-k;j++){ p=p->next; } return p; } } int main() { int k; linklist head,p; head=creatbyqueue(); /*尾插法建立带头结点的单链表*/ print(head); /*输出单链表head*/ printf("k="); scanf("%d",&k); p=search(head,k); if (p) printf("%d\n",p->info); else printf("Not Found!\n"); delList(head); return 0; }