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;
}