- 实验内容
(1)编程实现顺序表的如下操作,并设计菜单完成调用。
①表的建立、输出、求长度、取值、查找、插入、删除等基本操作(必做)
②表的逆置(要求利用原表的存储空间)。(选做)
③删除表中所有值为x的元素。(选做)
④将两个递增有序表合并成一个递增有序表。(算法2.16,P43)【考虑:数据不重复,或者合并为递减有序表的情况)】
(2)编程实现单链表的如下操作,并设计菜单完成调用。
①表的建立、输出、求长度、取值、查找、插入、删除等基本操作(必做)
②通过一次遍历确定表中值最大(或最小)的结点。(习题2.6,P53)。(必做)
③表的逆置(要求利用原表的存储空间)。(习题2.7,P53)。(选做)
④删除表中数据值大于mink且小于maxk的所有结点。(习题2.8,P53)
⑤将两个递增有序表合并成一个递增有序表。(算法2.17,P44)【考虑:数据不重复,或者合并为递减有序表的情况)】(选做)
(3)编程实现单循环链表或双向(循环)链表的基本操作(如:建立、输出、求长度、取值、查找、插入、删除等),并设计一个菜单调用。(选做)
- 编程实现顺序表的基本操作,并设计一个菜单调用。
- 程序结构、核心代码:
- comdef.h
- #include <stdio.h>
#include <iostream>
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -1
typedef int Status; - sqlistdef.H
-
//顺序表的存储结构
#define MAXSIZE 100 //顺序表可能达到的最大长度
typedef int ElemType;
typedef struct
{
ElemType *elem; //存储空间的基地址
int length; //当前长度
}SqList;//顺序表的结构类型
- sqlistapp.H
//顺序表的初始化
Status InitList(SqList &L)
{
int i,n;
L.elem=new ElemType[MAXSIZE]; //为顺序表动态分配一个大小为MAXSIZE的数组空间
if (!L.elem) return OVERFLOW; //分配失败则退出
cout<<"\n数据个数=";
cin>>n;
cout<<"\n输入"<<n<<"个数据: ";
for (i=0;i<n;i++)
cin>>L.elem[i];
L.length=n;
return OK;
}
//表的输出
void OutputList(SqList L){
int i;
for (i=0;i<L.length;i++) //依次访问顺序表(数组)的元素 ,输出
cout<<" "<<L.elem[i];
cout<<endl;
}
//表的求长度
int ListLength(SqList L)
{
return L.length;
}
//判断非空
bool ListEmpty(SqList L)
{
return L.length==0;
}
//取值
Status GetElem(SqList L,int i,ElemType &e)
{
if(i<1||i>L.length) //判断位置的合法性
return ERROR;
e=L.elem[i-1];//取表中序号为i的元素的值并用e带出
return OK;
}
//查找,此算法平均时间复杂度为O(n)
int LocateElem(SqList L,ElemType e)
{
for(int i=0;i<L.length;i++)
{
if(L.elem[i]==e) //查找表中与e相等的元素,并返回它的序号
return i+1;
}
return 0;
}
//表的插入
Status ListInsert(SqList &L,int i,ElemType e)//在第i个位置插入新元素e
{
int j;
if(i<1||i>L.length+1) return ERROR; // 判断插入位置的合法性
if(L.length==MAXSIZE) return ERROR;//判断储存空间是否已满
for(j=L.length-1;j>=i-1;j--) //将第i至第n个位置的元素依次后移
{
L.elem[j+1]=L.elem[j];
}
L.elem[i-1]=e; //空出第i个位置,赋值
++L.length;// 表长加一
return OK;
}
//表的删除
Status ListDelete(SqList &L,int i)
{
if(i<1||i>L.length) //判断删除位置的合法性
return ERROR;
for(int j=i;j<L.length;j++)
{
L.elem[j-1]=L.elem[j];//被删除元素之后的元素依次前移
}
--L.length;//表长减一
return OK;
}
//表的逆置
void ListRervese(SqList &L)
{
ElemType temp;
int i,j;
for(i=0,j=L.length-1;i<j;i++,j--)//由外向内,表两头的元素依次互换
{
temp=L.elem[i];
L.elem[i]=L.elem[j];
L.elem[j]=temp;
}
}
//删除表中所有值为e的元素(时间复杂度为O(n)、空间复杂度为O(1))
Status DeleteE(SqList &L,ElemType e)
{
int k=0;
for(int i=0;i<L.length;i++)
{
if(L.elem[i]!=e)
{
L.elem[k]=L.elem[i];//将数组中不为e的元素,覆盖原来值为e的元素
k++;
}
}
//判断是否成功删除了表中与e相同的元素
if(k!=L.length){
L.length=k;
} else{
return ERROR;
}
}
//有序表的合并
void MergeList_Sq(SqList L,SqList LA,SqList &LB,int &n)
{
//将两个递增的有序表L和LA合并成一个递增的有序表LB
ElemType *p,*pa,*pb,*p_last,*pa_last;
LB.length=L.length+LA.length;
LB.elem=new ElemType[LB.length];//为表LB动态分配空间
pb=LB.elem;
//p和pa分别指向两表的首元素
p=L.elem;
pa=LA.elem;
n=0;//两表中相同元素的个数
//p_last和pa_last分别指向两表的最后一个元素
p_last=L.elem+L.length-1;
pa_last=LA.elem+LA.length-1;
//LA和LB均未达到表尾时
while((p<=p_last)&&(pa<=pa_last))
{
//依次摘取值较小的插入LB的最后
if(*p<*pa)
{
*pb++=*p++;
}
else if(*p>*pa)
{
*pb++=*pa++;
}
//两值相等时取L的值
else
{
*pb++=*p++;
*pa++;
n++;
}
}
while(p<=p_last) *pb++=*p++;// LA已达到表尾,依次将L的剩余元素插入LB的最后
while(pa<=pa_last) *pb++=*pa++;//L已达到表尾,依次将LA的剩余元素插入LB的最后
}
//表的摧毁
void DestroyList(SqList &L)
{
delete []L.elem;
L.elem=NULL;
L.length=0;
}
- main.CPP
int main()
{
SqList L;
ElemType e;
int choice,i;
cout<<"\n建立数据表:";
if (InitList(L)==OVERFLOW)
{
cout<<"数据表空间分配失败,程序退出!";
return 0;
}
else
{
cout<<"数据表建立成功,数据表为:";
OutputList(L);
}
//菜单
do
{
cout<<"\n\n===================================";
cout<<"\n 顺序表的基本操作 ";
cout<<"\n===================================";
cout<<"\n 1:表的输出" ;
cout<<"\n 2:求表的长度" ;
cout<<"\n 3:判断空表" ;
cout<<"\n 4:取表中元素" ;
cout<<"\n 5:查找表中元素" ;
cout<<"\n 6:插入元素" ;
cout<<"\n 7:删除元素" ;
cout<<"\n 8:表的逆置" ;
cout<<"\n 9:删除表中为e的元素" ;
cout<<"\n 10:将两个递增的有序表L和LA合并成一个递增的有序表LB" ;
cout<<"\n 0:操作结束" ;
cout<<"\n===================================";
cout<<"\n请输入你的选择:";
cin>>choice;
switch (choice)
{
case 1: cout<<"\n数据表为:";
OutputList(L);
break;
case 2: cout<<"\n数据表的长度为:"<<ListLength(L);
break;
case 3: if( ListEmpty(L))
cout<<"\n数据表为空表";
else
cout<<"\n数据表为非空表";
break;
case 4:
cout<<"输入位置";
cin>>i;
if(!GetElem(L,i,e))
cout<<"\n位置不合法";
else
cout<<"\n取值成功,第"<<i<<"个位置的元素是"<<e;
break;
case 5:
cout<<"\n输入待查找的数据:";
cin>>e;
if(!LocateElem(L,e))
cout<<"\n查找失败";
else
cout<<"\n查找成功,"<<e<<"在数据表中第"<<LocateElem(L,e)<<"个位置";
break;
case 6: cout<<"\n插入元素的位置和值";
cin>>i>>e;
if(ListInsert(L,i,e))
{
cout<<"\n插入成功!";
cout<<"\n插入后的数据表为:";
OutputList(L);
}
else
cout<<"\n插入位置不合法或储存空间已满";
break;
case 7: cout<<"\n删除元素的位置";
cin>>i;
if(ListDelete(L,i))
{
cout<<"\n删除成功!";
cout<<"\n删除后的数据表:";
OutputList(L);
}
else
cout<<"\n插入位置不合法";
break;
case 8:ListRervese(L);
cout<<"逆置后的数据表为:";
OutputList(L);
break;
case 9:cout<<"需要删除的元素为:";
cin>>e;
if((DeleteE(L,e))==ERROR)
{
cout<<"\n表中无该元素";
}
else
{
cout<<"\n删除成功!";
cout<<"\n删除后的数据表:";
OutputList(L);
}
break;
case 10: SqList LA,LB;
int n;
cout<<"\n建立数据表LA:";
if (InitList(LA)==OVERFLOW){
cout<<"数据表空间分配失败,程序退出!";
return 0;
}else{
cout<<"数据表建立成功,数据表为:";
OutputList(LA);
}
MergeList_Sq(L,LA,LB,n);
cout<<"\n合并后的数据表为:";
for(i=0;i<LB.length-n;i++)
{
cout<<LB.elem[i]<<" ";
}
break;
case 0: break;
default:cout<<"\n输入错误,重新输入!";
}
} while (choice) ;
DestroyList(L);
return 0;
}
2. 编程实现单链表的基本操作,并设计一个菜单调用。
(1)程序结构、核心代码:
①comdef.h
#include <stdio.h>
#include <iostream>
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -1
typedef int Status;
linkkistdef.H
typedef int ElemType;
//单链表的存储结构
typedef struct LNode
{
ElemType data;//结点的数据域
struct LNode *next;//结点的指针域
}LNode,*LinkList; //LinkList为指向结构体LNode的指针类型
linklistaoo.H
//建立单链表(后插法) ,该算法时间复杂度为O(n)
Status InitList(LinkList& L)
{
LinkList p,r;
int i,n;
L=new LNode; //生成新结点作为头结点,用头指针L指向头结点
L->next=NULL;//建立一个带头结点的空链表
r=L;//尾指针r指向头结点
cout<<"\n数据个数=";
cin>>n;
cout<<"\n输入"<<n<<"个数据: ";
for (i=0;i<n;i++)
{
p=new LNode; //生成新结点
cin>>p->data;//输入元素值赋给新结点的数据域
r->next=p;
p->next=NULL;//将新结点*p插在表尾
r=p; //修改尾指针
}
return OK;
}
//输出单链表 ,该算法时间复杂度为O(1)
void OutputList(LinkList L)
{
LinkList p;
p=L->next;//头结点指向p
while (p)
{
cout<<" "<<p->data;
p=p->next;
}
}
//表的求长度,该算法时间复杂度为O(1)
Status ListLength(LinkList L)
{
int j=0;
LinkList p;
p=L->next;
while(p)
{
j++;
p=p->next;
}
return j;
}
//判断非空,该算法时间复杂度为O(1)
bool ListEmpty(LinkList L )
{
return L->next==NULL;
}
//取表中元素,该算法时间复杂度为O(n)
Status GetElem(LinkList L,int i,ElemType &e)
{
//取第i个结点的值,并用e保存此数据域
LinkList p;
p=L->next;//初始化,p指向首元结点
int j=1;//计数器赋值为1
while(p&&j<i) //顺链域向后扫描,直到p为空或p指向第i个元素
{
p=p->next;//p指向下一个结点
++j;
}
if(!p&&j>i)// 判断i的合法性
{
return ERROR;
}
e=p->data;//取第i个结点的数据域
return OK;
}
//查找表中元素,该算法时间复杂度为O(n)
Status LocateElem(LinkList L,ElemType e)
{
LinkList p;
p=L->next;//初始化,p指向首元结点
//int i=1;//计数器赋值为1
while(p && p->data!=e)//顺链域向后扫描,直到p为空或p所指结点的数据域等于e
{
p=p->next;
//i++;
}
//if(!p) return 0;
//else return i;
return p;
}
//插入元素,该算法时间复杂度为O(n)
Status ListInsert(LinkList &L,int i,ElemType e)
{
//将数据域为e的新结点插入第i个结点的位置上(在结点i-1与i之间)
LinkList s,p;
p=L;
int j=0;
while(p && (j<i-1))//查找第i-1个结点(该位置的前驱结点),p指向该结点
{
p=p->next;
++j;
}
//判断i的值是否合法
if(!p||j>i-1) return ERROR;// 判断i的合法性
s=new LNode;//生成一个数据域为e的新结点*s
s->data=e;
s->next=p->next;//将结点*s的指针域指向第i个结点
p->next=s;//将结点*p的指针域指向结点*s
return OK;
}
//删除元素,该算法时间复杂度为O(n)
Status ListDelete(LinkList &L,int i,ElemType &e)
{
LinkList p,q;
p=L;
int j=0;
while((p->next)&&(j<i-1))//查找第i-1个结点(该位置的前驱结点),p指向该结点
{
p=p->next;
++j;
}
//判断i位置是否合理
if(!(p->next)||(j>i-1)) return ERROR;
q=p->next;//用q临时保存被删结点的地址以备释放
e=q->data;
p->next=q->next;//改变删除结点前驱结点的指针域
delete q;//释放删除结点的空间
return OK;
}
//获取表中元素值最大的结点的位置
Status MaxNode(LinkList L)
{
LinkList p = L->next;
int max=p->data;
int i = 1,maxnode;
while(p)
{
if(p->data >max)//当前结点的数据域与最大元素值相比
{
max = p->data;
maxnode = i;
}
p = p->next;
++i;
}
return maxnode;
}
//逆置单链表(用头插法思想)
void ReverseList(LinkList &L)
{
LinkList p,q;//q指向次首元结点,p指向首元结点
p=L->next;
L->next=NULL;
while(p)
{
q=p;//q指向将被逆序链接的结点
p=p->next;//q指向下一结点
/*头插法 */
q->next=L->next;
L->next=q;
}
}
//删除表中比mink大且比maxk小的结点
Status DeleteNode(LinkList &L,ElemType mink,ElemType maxk)
{
LinkList p,q;//p为首元结点,q为头结点
p=L->next;
q=L;
if(mink>=maxk)//判断mink与maxk的输入是否合理
{
return ERROR;
}
else
{
while(p!=NULL)
{
if((p->data>mink)&&(p->data<maxk))
{
q->next=p->next;//满足条件则删除p结点
//释放空间
delete(p);
p=q->next;
}
else
{
//若不满足条件则p,q后移一位
q=q->next;
p=p->next;
}
}
return OK;
}
}
//合并两个递增有序单链表L和LA为一个LB
void MergeList_L(LinkList &L,LinkList &LA,LinkList &LB){
LinkList p,pa,pb;
//pa和p的初值分别指向两个表的首元结点
p=L->next;
pa=LA->next;
LB=L; //用L的头结点做为LB的头结点
pb=LB;//pb的初值指向LB的头结点
while(p&&pa)
{
//L和LA均未达到表尾,依次摘取较小结点插入LB的最后
if((p->data)<(pa->data)){
pb->next=p;
pb=p;
p=p->next;
}else if((p->data)>(pa->data)){
pb->next=pa;
pb=pa;
pa=pa->next;
}else
{
pb->next=p;
pb=p;
p=p->next;
pa=pa->next;//相等时摘取L的结点,但同时pa也需后移
}
}
//将非空表的剩余部分插入到pc所指结点之后
pb->next=p?p:pa;
delete LA;
}
//摧毁单链表
Status DestroyList(LinkList &L)
{
LinkList p;
while (L)
{
p=L;
L=L->next;
delete p;
}
L=NULL;
return OK;
}
main.CPP
#include "comdef.h"
#include "linklistdef.h"
#include "linklistapp.h"
int main(){
LinkList L;
int i;
ElemType e,maxnode,minnode,mink,maxk;
int choice;
cout<<"\n建立数据表:";
if (InitList(L)==OVERFLOW){
cout<<"数据表空间分配失败,程序退出!";
return 0;
}
else{
cout<<"数据表建立成功,数据表为:";
OutputList(L);
}
do {
cout<<"\n\n===================================";
cout<<"\n 单链表的基本操作 ";
cout<<"\n===================================";
cout<<"\n 1:表的输出" ;
cout<<"\n 2:求表的长度" ;
cout<<"\n 3:判断空表" ;
cout<<"\n 4:取表中元素" ;
cout<<"\n 5:查找表中元素" ;
cout<<"\n 6:插入元素" ;
cout<<"\n 7:删除元素" ;
cout<<"\n 8:获取数据值最大的节点" ;
cout<<"\n 9:表的逆置" ;
cout<<"\n 10:删除表中数据值大于mink且小于maxk的所有结点" ;
cout<<"\n 11:合并两个递增有序表为一个递增有序表(数据不重复)" ;
cout<<"\n 0:操作结束" ;
cout<<"\n===================================";
cout<<"\n请输入你的选择:";
cin>>choice;
switch (choice){
case 1: cout<<"\n单链表为:";
OutputList(L);
break;
case 2: cout<<"\n单链表的长度为:"<<ListLength(L);
break;
case 3: if(ListEmpty(L)==OK){
cout<<"\n该表是空表";
}else{
cout<<"\n该表不是空表";
}
break;
case 4: cout<<"\n所取元素的序号为:";
cin>>i;
if((GetElem(L,i,e))==ERROR){
cout<<"\n输入不合法!";
}else{
cout<<"\n取出的元素值为:"<<e;
}
break;
case 5: cout<<"\n输入查找元素的值:";
cin>>e;
i=LocateElem(L,e);
if(i==0){
cout<<"\n查找失败!";
}else{
cout<<"\n"<<e<<"在表中位于第"<<i<<"个";
}
break;
case 6: cout<<"\n输入插入的元素的位置以及元素的值:";
cin>>i>>e;
if((ListInsert(L,i,e))==ERROR)
{
cout<<"\n插入失败,输入的值不合法!";
}else
{
cout<<"\n插入成功,数据表为:";
OutputList(L);
}
break;
case 7: cout<<"\n输入删除的元素的位置:";
cin>>i;
if((ListDelete(L,i,e))==ERROR)
{
cout<<"\n输入的位置不合理!";
}else{
cout<<"\n删除成功,删除的元素是:"<<e;
cout<<"\n删除后的数据表为:";
OutputList(L);
}
break;
case 8: cout<<"\n表中数据元素最大值对应的节点为:"<<MaxNode(L);
break;
case 9: cout<<"\n逆置后的数据表为:";
ReverseList(L);
OutputList(L);
break;
case 10:cout<<"\n输入mink的值:";
cin>>mink;
cout<<"\n输入maxk的值:";
cin>>maxk;
if((DeleteNode(L,mink,maxk))==ERROR){
cout<<"\n输入值不合法!";
}else{
cout<<"\n删除后数据表为:";
OutputList(L);
}
break;
case 11:LinkList LA,LB;
cout<<"\n建立数据表LA:";
if (InitList(LA)==OVERFLOW){
cout<<"数据表空间分配失败,程序退出!";
return 0;
}
else{
cout<<"数据表建立成功,数据表为:";
OutputList(LA);
}
MergeList_L(L,LA,LB);
cout<<"\n合并后的数据表L为:";
OutputList(L);
break;
case 0: break;
default:cout<<"\n输入错误,重新输入!";
}
} while (choice) ;
DestroyList(L);
return 0;
}