一、 实验目的
1.掌握编程环境的使用。
2.能够分析线性表两种存储方式的优缺点。
3.具备在不同适用条件下选取顺序表及链表解决问题的能力。
二、 实验环境
⒈ 硬件:每个学生需配备计算机一台。操作系统:Windows;
⒉ 软件:Windows操作系统+Turbo C\C++等
三、 实验要求
1.实现顺序表的存储结构和顺序表的基本运算以及有序顺序表的合并算法。
2.实现链表的存储结构和链表的基本运算以及有序单链表的合并算法。
3.由主函数按照用户要求对各个模块操作访问。
4.一元多项式的相加可参见课本实例,或者自己设计实例。
5.每次操作之前要有明确的说明,操作后要输出操作结果。
四、 实验内容
1.顺序表及单链表的数据结构建立实现;
2.顺序表及单链表元素插入操作实现;
3.顺序表及单链表元素删除操作实现;
4.实现一元多项式的相加。
五、思考题
1. 如何实现单链表就地逆置操作。
2. 建立一个循环链表,并且实现插入、删除操作。
3. 建立一个双向循环链表,在双向循环链表中实现基本操作。
4.将两个递增的单链表合并成一个非递减的单链表。
六、 代码
#include<st#include<stdio.h>
#include<stdlib.h>
#define Size 5 //申请空间大小
typedef struct{
int * elem; //声明了一个不确定长度的数组
int length; //当前顺序表的长度
int size; //当前分配的存储容量
}Table;
//顺序表的创建和初始化
Table InitList(Table t){
t.elem = (int*)malloc(Size*sizeof(int)); //构造一个空的顺序表,动态申请存储空间
if(!t.elem){ //如果申请失败,作出提示并直接退出程序
printf("初始化失败");
exit(0);
}
t.length = 0; //空表的长度初始化为0
t.size = Size; //空表的初始存储空间为Size
return t;
}
//输出顺序表中的元素
void displayTable(Table t){
for(int i = 0; i < t.length; i++){
printf("%d ",t.elem[i]);
}
printf("\n");
}
//顺序表的插入
Table ListInsert(Table t,int elem, int index){
if(index < 1 || index > t.length + 1){
printf("插入位置有问题");
return t;
}
if(t.length >= t.size){ //判断顺序表是否有多余空间,若不够,需要申请
t.elem = (int *)realloc(t.elem,(t.size+1)*sizeof(int));
if(!t.elem){
printf("存储分配失败\n");
return t;
}
t.size++;
}
//插入操作,需要将从插入位置开始的后续元素逐步后移
for(int i = t.length - 1; i >= index - 1; i--){
t.elem[i+1] = t.elem[i];
}
//后移完成后把所需插入的元素添加到顺序表的相应位置
t.elem[index-1] = elem;
t.length++; //表长加一
return t;
}
//顺序表的删除
Table ListDelete(Table t, int index){
if(index > t.length || index < 1){
printf("被删除元素的位置有误\n");
return t;
}
//删除操作
for(int i = index; i < t.length; i++){
t.elem[i-1] = t.elem[i];
}
t.length--;
return t;
}
int main(){
Table t1 = InitList(t1);
//向顺序表中添加元素
for (int i = 1; i <= Size; i++){
t1.elem[i-1] = i;
t1.length++;
}
printf("顺序表中存储的元素为:\n");
displayTable(t1);
printf("在第2的位置插入6:\n");
t1 = ListInsert(t1,6,2);
displayTable(t1);
printf("删除元素1:\n");
t1 = ListDelete(t1, 1);
displayTable(t1);
return 0;
}
//单链表的操作代码如下
#include<stdio.h>
#include<stdlib.h>
//链表存储结构
typedef struct Link{
int elem; //数据域
struct Link * next; //指针域,指向直接后继元素
}Link; //link为节点名
Link * initLink();
Link * insertElem(Link * p, int elem, int index);//p是链表,elem是插入结点的数据域,index是插入位置
Link * delElem(Link * p, int index);
void display(Link * p);
//链表的创建和初始化
Link * initLink(){
Link * p = (Link*)malloc(sizeof(Link)); //创建一个头结点
Link * temp = p; //声明一个指针指向头结点,用于遍历链表
//生成链表
for(int i = 1; i < 5; i++){
//创建结点并初始化
Link * a = (Link*)malloc(sizeof(Link));
a->elem = i;
a->next = NULL;
//建立新结点与直接前驱结点的逻辑关系
temp->next = a;
temp = temp->next;
}
return p;
}
//插入操作
Link * insertElem(Link * p, int elem, int index){
Link * temp = p; //创建临时结点temp
//首先找到要插入位置上的一个结点
for(int i = 1; i < index; i++){
temp = temp->next;
if(temp == NULL){
printf("插入位置无效\n");
return p;
}
}
//创建结点c
Link * c = (Link*)malloc(sizeof(Link));
c->elem = elem;
//向链表中插入结点
c->next = temp->next;
temp->next = c;
return p;
}
//删除操作
Link * delElem(Link * p, int index){
Link * temp = p;
//遍历被删除结点的上一个结点
for(int i = 1; i < index; i++){
temp = temp->next;
if(temp->next == NULL){
printf("没有该结点");
return p;
}
}
Link * del = temp->next; //单独设置一个指针指向被删除结点,以防丢失
temp->next = temp->next->next; //删除某个结点的方法就是更改前一个结点的指针域
free(del); //手动释放该结点,防止内存泄漏
return p;
}
//打印
void display(Link *p){
Link * temp = p; //将temp指针重新指向头结点
//只要temp指针指向的结点的next不是NULL,就执行输出语句
while(temp->next){
temp = temp->next;
printf("%d ",temp->elem);
}
printf("\n");
}
int main(){
printf("初始链表为:");
Link * p = initLink();
display(p);
printf("在第4的位置上插入元素6:\n");
p = insertElem(p, 6, 4);
display(p);
printf("删除元素3\n");
p = delElem(p, 3);
display(p);
printf("\n");
}
//一元多项式的操作代码如下
#include<stdio.h>
/*
一元多项式相加
*/
#include<stdlib.h>
#define LEN sizeof(Poly)
typedef struct term{
float coef; //系数
int expn; //指数
struct term *next;
}Poly,*Link;
void CreatePolyn(Link *p,int m);
void PrintPolyn(Link p);
int cmp(Link p1, Link p2);
Link AddPolyn(Link pa, Link pb);
int main()
{
Link P1,P2;
int L1,L2;
printf("请输入第一个多项式的项数:");
scanf("%d",&L1);
CreatePolyn(&P1,L1);
printf("第一个多项式为:");
PrintPolyn(P1);
printf("请输入第二个多项式的项数:");
scanf("%d",&L2);
CreatePolyn(&P2,L2);
printf("第二个多项式为:");
PrintPolyn(P2);
printf("\n");
printf("两个一元多项式相加的结果为:");
PrintPolyn(AddPolyn(P1, P2));
}
void CreatePolyn(Link *p,int m)//*p是双重指针,用此意在改变指针
//创建多项式(带头结点),基础:动态链表的创建
{
Link r,s;
int i;
*p=(Link)malloc(LEN);
r=*p;
for(i=0;i<m;i++)
{
s=(Link)malloc(LEN);
printf("输入系数和指数(以空格隔开):");
scanf("%f %d", &s->coef, &s->expn);
r->next=s;
r=s;
}
r->next=NULL;
}
void PrintPolyn(Link p)
//打印显示多项式,基础:遍历链表
{
Link s;
s = p->next;
while(s)
{
printf("%.2f X^%d", s->coef, s->expn);
s = s->next;
if(s!=NULL) //是正数则用'+'连接两项,是负数则直接用负数的负号'-'连接两项
if(s->coef>=0) printf("+");
}
printf("\n");
}
int cmp(Link a, Link b)
//比较两项的指数的大小,并返回特定的值。
{
if (a->expn<b->expn) return -1;
else if(a->expn == b->expn) return 0;
else return 1;
}
Link AddPolyn(Link pa, Link pb)//pa, pb是两个指向头结点的指针
//两个多项式相加得一个新多项式,并且返回新多项式的头结点的指针
{
Link newp, p, q, s, pc;
float sum;
p = pa->next; //p指向pa的第一个元素
q = pb->next; //q指向pb的第一个元素
newp=(Link)malloc(LEN); //pc指向新多项式pc的头结点
pc = newp;
while(p&&q){
switch(cmp(p, q))
{
case -1: //若指数:p<q,则将p所指结点链入头结点为newp的链表中,且p向后遍历
s = (Link)malloc(LEN);
s->coef = p->coef;
s->expn = p->expn;
pc->next = s;
pc = s;
p = p->next;
break;
case 0://若比较两项的指数相等,则将两项系数相加后得到的项放入头结点为newp的链表中 ,且p,q同时向后遍历
sum = p->coef+q->coef;
if(sum!=0.0)//若两项系数相加为0,则不放入头结点为newp的链表中
{
s = (Link)malloc(LEN);
s->coef = sum;
s->expn = p->expn;
pc->next = s;
pc = s;
}
p = p->next;
q = q->next;
break;
case 1: //若指数:q<p,则将q所指结点链入头结点为newp的链表中,且q向后遍历
s = (Link)malloc(LEN);
s->coef = q->coef;
s->expn = q->expn;
pc->next = s;
pc = s;
q = q->next;
break;
}
}
while(p) //若p所在链表还有剩余项,直接将剩余项依次链入头结点为newp的链表中
{
s = (Link)malloc(LEN);
s->coef = p->coef;
s->expn = p->expn;
pc->next = s;
pc = s;
p = p->next;
}
while(q)//若q所在链表还有剩余项,直接将剩余项依次链入头结点为newp的链表中
{
s = (Link)malloc(LEN);
s->coef = q->coef;
s->expn = q->expn;
pc->next = s;
pc = s;
q = q->next;
}
pc->next = NULL;
return newp; //返回新多项式的首地址
}
dio.h>
#include<stdlib.h>
#define Size 5 //申请空间大小
typedef struct{
int * elem; //声明了一个不确定长度的数组
int length; //当前顺序表的长度
int size; //当前分配的存储容量
}Table;
//顺序表的创建和初始化
Table InitList(Table t){
t.elem = (int*)malloc(Size*sizeof(int)); //构造一个空的顺序表,动态申请存储空间
if(!t.elem){ //如果申请失败,作出提示并直接退出程序
printf("初始化失败");
exit(0);
}
t.length = 0; //空表的长度初始化为0
t.size = Size; //空表的初始存储空间为Size
return t;
}
//输出顺序表中的元素
void displayTable(Table t){
for(int i = 0; i < t.length; i++){
printf("%d ",t.elem[i]);
}
printf("\n");
}
//顺序表的插入
Table ListInsert(Table t,int elem, int index){
if(index < 1 || index > t.length + 1){
printf("插入位置有问题");
return t;
}
if(t.length >= t.size){ //判断顺序表是否有多余空间,若不够,需要申请
t.elem = (int *)realloc(t.elem,(t.size+1)*sizeof(int));
if(!t.elem){
printf("存储分配失败\n");
return t;
}
t.size++;
}
//插入操作,需要将从插入位置开始的后续元素逐步后移
for(int i = t.length - 1; i >= index - 1; i--){
t.elem[i+1] = t.elem[i];
}
//后移完成后把所需插入的元素添加到顺序表的相应位置
t.elem[index-1] = elem;
t.length++; //表长加一
return t;
}
//顺序表的删除
Table ListDelete(Table t, int index){
if(index > t.length || index < 1){
printf("被删除元素的位置有误\n");
return t;
}
//删除操作
for(int i = index; i < t.length; i++){
t.elem[i-1] = t.elem[i];
}
t.length--;
return t;
}
int main(){
Table t1 = InitList(t1);
//向顺序表中添加元素
for (int i = 1; i <= Size; i++){
t1.elem[i-1] = i;
t1.length++;
}
printf("顺序表中存储的元素为:\n");
displayTable(t1);
printf("在第2的位置插入6:\n");
t1 = ListInsert(t1,6,2);
displayTable(t1);
printf("删除元素1:\n");
t1 = ListDelete(t1, 1);
displayTable(t1);
return 0;
}
//单链表的操作代码如下
#include<stdio.h>
#include<stdlib.h>
//链表存储结构
typedef struct Link{
int elem; //数据域
struct Link * next; //指针域,指向直接后继元素
}Link; //link为节点名
Link * initLink();
Link * insertElem(Link * p, int elem, int index);//p是链表,elem是插入结点的数据域,index是插入位置
Link * delElem(Link * p, int index);
void display(Link * p);
//链表的创建和初始化
Link * initLink(){
Link * p = (Link*)malloc(sizeof(Link)); //创建一个头结点
Link * temp = p; //声明一个指针指向头结点,用于遍历链表
//生成链表
for(int i = 1; i < 5; i++){
//创建结点并初始化
Link * a = (Link*)malloc(sizeof(Link));
a->elem = i;
a->next = NULL;
//建立新结点与直接前驱结点的逻辑关系
temp->next = a;
temp = temp->next;
}
return p;
}
//插入操作
Link * insertElem(Link * p, int elem, int index){
Link * temp = p; //创建临时结点temp
//首先找到要插入位置上的一个结点
for(int i = 1; i < index; i++){
temp = temp->next;
if(temp == NULL){
printf("插入位置无效\n");
return p;
}
}
//创建结点c
Link * c = (Link*)malloc(sizeof(Link));
c->elem = elem;
//向链表中插入结点
c->next = temp->next;
temp->next = c;
return p;
}
//删除操作
Link * delElem(Link * p, int index){
Link * temp = p;
//遍历被删除结点的上一个结点
for(int i = 1; i < index; i++){
temp = temp->next;
if(temp->next == NULL){
printf("没有该结点");
return p;
}
}
Link * del = temp->next; //单独设置一个指针指向被删除结点,以防丢失
temp->next = temp->next->next; //删除某个结点的方法就是更改前一个结点的指针域
free(del); //手动释放该结点,防止内存泄漏
return p;
}
//打印
void display(Link *p){
Link * temp = p; //将temp指针重新指向头结点
//只要temp指针指向的结点的next不是NULL,就执行输出语句
while(temp->next){
temp = temp->next;
printf("%d ",temp->elem);
}
printf("\n");
}
int main(){
printf("初始链表为:");
Link * p = initLink();
display(p);
printf("在第4的位置上插入元素6:\n");
p = insertElem(p, 6, 4);
display(p);
printf("删除元素3\n");
p = delElem(p, 3);
display(p);
printf("\n");
}
//一元多项式的操作代码如下
#include<stdio.h>
/*
一元多项式相加
*/
#include<stdlib.h>
#define LEN sizeof(Poly)
typedef struct term{
float coef; //系数
int expn; //指数
struct term *next;
}Poly,*Link;
void CreatePolyn(Link *p,int m);
void PrintPolyn(Link p);
int cmp(Link p1, Link p2);
Link AddPolyn(Link pa, Link pb);
int main()
{
Link P1,P2;
int L1,L2;
printf("请输入第一个多项式的项数:");
scanf("%d",&L1);
CreatePolyn(&P1,L1);
printf("第一个多项式为:");
PrintPolyn(P1);
printf("请输入第二个多项式的项数:");
scanf("%d",&L2);
CreatePolyn(&P2,L2);
printf("第二个多项式为:");
PrintPolyn(P2);
printf("\n");
printf("两个一元多项式相加的结果为:");
PrintPolyn(AddPolyn(P1, P2));
}
void CreatePolyn(Link *p,int m)//*p是双重指针,用此意在改变指针
//创建多项式(带头结点),基础:动态链表的创建
{
Link r,s;
int i;
*p=(Link)malloc(LEN);
r=*p;
for(i=0;i<m;i++)
{
s=(Link)malloc(LEN);
printf("输入系数和指数(以空格隔开):");
scanf("%f %d", &s->coef, &s->expn);
r->next=s;
r=s;
}
r->next=NULL;
}
void PrintPolyn(Link p)
//打印显示多项式,基础:遍历链表
{
Link s;
s = p->next;
while(s)
{
printf("%.2f X^%d", s->coef, s->expn);
s = s->next;
if(s!=NULL) //是正数则用'+'连接两项,是负数则直接用负数的负号'-'连接两项
if(s->coef>=0) printf("+");
}
printf("\n");
}
int cmp(Link a, Link b)
//比较两项的指数的大小,并返回特定的值。
{
if (a->expn<b->expn) return -1;
else if(a->expn == b->expn) return 0;
else return 1;
}
Link AddPolyn(Link pa, Link pb)//pa, pb是两个指向头结点的指针
//两个多项式相加得一个新多项式,并且返回新多项式的头结点的指针
{
Link newp, p, q, s, pc;
float sum;
p = pa->next; //p指向pa的第一个元素
q = pb->next; //q指向pb的第一个元素
newp=(Link)malloc(LEN); //pc指向新多项式pc的头结点
pc = newp;
while(p&&q){
switch(cmp(p, q))
{
case -1: //若指数:p<q,则将p所指结点链入头结点为newp的链表中,且p向后遍历
s = (Link)malloc(LEN);
s->coef = p->coef;
s->expn = p->expn;
pc->next = s;
pc = s;
p = p->next;
break;
case 0://若比较两项的指数相等,则将两项系数相加后得到的项放入头结点为newp的链表中 ,且p,q同时向后遍历
sum = p->coef+q->coef;
if(sum!=0.0)//若两项系数相加为0,则不放入头结点为newp的链表中
{
s = (Link)malloc(LEN);
s->coef = sum;
s->expn = p->expn;
pc->next = s;
pc = s;
}
p = p->next;
q = q->next;
break;
case 1: //若指数:q<p,则将q所指结点链入头结点为newp的链表中,且q向后遍历
s = (Link)malloc(LEN);
s->coef = q->coef;
s->expn = q->expn;
pc->next = s;
pc = s;
q = q->next;
break;
}
}
while(p) //若p所在链表还有剩余项,直接将剩余项依次链入头结点为newp的链表中
{
s = (Link)malloc(LEN);
s->coef = p->coef;
s->expn = p->expn;
pc->next = s;
pc = s;
p = p->next;
}
while(q)//若q所在链表还有剩余项,直接将剩余项依次链入头结点为newp的链表中
{
s = (Link)malloc(LEN);
s->coef = q->coef;
s->expn = q->expn;
pc->next = s;
pc = s;
q = q->next;
}
pc->next = NULL;
return newp; //返回新多项式的首地址
}
七、 运行结果截图