数据结构实验 xpp
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
学生学号0120809320515 实验课成绩
数据结构实验设计报告书
实验课程名称数据结构
开课学院计算机学院
指导教师姓名王晟
学生姓名陈小攀
学生专业班级通信0805
2009——2010学年第1 学期
实验1:单链表实验
一、实验目的
1.学会定义单链表的结点类型,实现对单链表的一些基本操作和具体
的函数定义,了解并掌握单链表的类定义以及成员函数的定义与调用。
2.掌握单链表基本操作及两个有序表归并、单链表逆置等操作的实现。
二、实验要求
1.预习C语言中结构体的定义与基本操作方法。
2.对单链表的每个基本操作用单独的函数实现。
3.编写完整程序完成下面的实验内容并上机运行。
三、实验内容
1.编写程序完成单链表的下列基本操作:
(1) 初始化单链表La。
(2) 在La中插入一个新结点。
(3) 删除La中的某一个结点。
(4) 在La中查找某结点并返回其位置。
(5) 打印输出La中的结点元素值。
2.构造两个带有表头结点的有序单链表La、Lb,编写程序实现将La、Lb合并成一个有序单链表Lc。
合并思想是:程序需要3个指针:pa、pb、pc,其中pa,pb分别指向La表与Lb表中当前待比较插入的结点,pc 指向Lc表中当前最后一个结点。
依次扫描La和Lb中的元素,比较当前元素的值,将较小者链接到*pc之后,如此重复直到La或Lb结束为止,再将另一个链表余下的内容链接到pc所指的结点之后。
3.构造一个单链表L,其头结点指针为head,编写程序实现将L逆置。
(即最后一个结点变成第一个结点,原来倒数第二个结点变成第二个结点,如此等等。
)
四、思考与提高
1.如果上面实验内容2中合并的表内不允许有重复的数据该如何操作?
2.如何将一个带头结点的单链表La分解成两个同样结构的单链表Lb,Lc,使得Lb中只含La表中奇数结点,Lc中含有La表的偶数结点?
#include <iostream> using namespace std; typedef struct node { char data;
struct node *next;}link;
link * get(link *l, int i)
{ link *p;int j=0;
p=l;
while((j<i) && (p->next!=NULL))
{p=p->next;j++;}
if(j==i) return p;
else return NULL;
}
link * ins (link *l, char ch,int i)
{ link *p,*s;
p=get(l,i-1);
if(p==NULL) cout<<"输入有误"<<endl; else { s=(link *)malloc(sizeof(link));
s->data=ch;
s->next=p->next;
p->next=s; }
return l;
}
link * find(link *l, char ch)
{ link *p; int i=0; int j=0;
p=l;
while(p!=NULL)
{ i++;
if(p->data!=ch) p=p->next;
else {cout<<"您查找的数据在第"<<i-1<<"个位置."<<endl;
j=1;p=p->next;
} }
if(j!=1) cout<<"您查找的数据不在线性表中."<<endl;
return l;
}
link * del(link *l, int i)
{ link *p,*s;
p=get(l,i-1);
if(p==NULL) cout<<"输入有误"<<endl; else {
s=p->next;
p->next=s->next;
free(s);
}
return l;
}
link * add(link *l )
{ link *p,*s;
cout<<"请输入一串单字符数据,以*结束!"<<endl;
char ch;
link *HEAD;
link *R,*P,*L;
HEAD=(link *)malloc(sizeof(link)); HEAD->next=NULL;
R=HEAD;
getchar();
ch=getchar();
while(ch!='*')
{
P=(link *)malloc(sizeof(link));
P->data=ch;P->next=NULL;
R->next=P;R=R->next;
getchar();
ch=getchar();
}
L=HEAD;
cout<<"当前输入的线性表为:"<<endl; P=L;P=P->next;
if(L!=NULL)
do {cout<<P->data<<" ";
P=P->next;
}while(P!=NULL);
cout<<endl;
p=l;
while(p->next!=NULL)
p=p->next;
s=L;
p->next=s->next;
p=l;
return l;
}
link * print(link *l)
{ int i,k;
char ch;
link *p,*q;
cout<<"当前线性表为:"<<endl;
p=l;p=p->next;
if(l!=NULL)
do
{cout<<p->data<<" ";
p=p->next;
}while(p!=NULL);
cout<<endl;
cout<<"请选择您要的操作:";
cout<<" 1、插入";
cout<<" 2、查找";
cout<<" 3、删除";
cout<<" 4、合并";
cout<<" 0、退出";
cout<<endl;
cin>>k;
if(k==1)
{
cout<<"请输入您要插入的数据值:"; cin>>ch;
cout<<"请输入您要插入的位置:"; cin>>i;
p=ins(l,ch,i);
q=print(l);
}
else if(k==2)
{
cout<<"请输入您要查找的数据值:"; cin>>ch;
p=find(l,ch);
q=print(l);
}
else if(k==3)
{
cout<<"请输入您要删除的数据的位置:"; cin>>i;
p=del(l,i);
q=print(l);
}
else if(k==4)
{ p=add(l);
q=print(l);
}
else if(k==0)
;
else
{cout<<"输入错误!"<<endl;
q=print(l);}
return l;
}
int main()
{
cout<<"请输入一串单字符数据,以*结束!"<<endl;
char ch;
//link *head;
link *r,*p,*q,*l;
l=(link *)malloc(sizeof(link));
l->next=NULL;
r=l;
ch=getchar();
// getchar();
while(ch!='*')
{
p=(link *)malloc(sizeof(link));
p->data=ch;p->next=NULL;
r->next=p;r=r->next;
ch=getchar();
// getchar();
}
//l=head;
q=print(l);
return 0;
}
实验2:栈的操作实验
一、实验目的1.熟悉并能实现栈的定义和基本操作。
2.了解和掌握栈在递归和非递归算法的应用。
二、实验要求1.进行栈的基本操作时要注意栈“后进先出”的特性。
2.编写完整程序完成下面的实验内容并上机运行。
三、实验内容
1.编写程序任意输入栈长度和栈中的元素值,构造一个顺序栈,对其进行清空、销毁、入栈、出栈以及取栈顶元素操作。
2.编写程序实现表达式求值,即验证某算术表达式的正确性,若正确,则计算该算术表达式的值。
主要功能描述如下:1、从键盘上输入表达式。
2、分析该表达式是否合法:
(1) 是数字,则判断该数字的合法性。
若合法,则压入数据到堆栈中。
(2) 是规定的运算符,则根据规则进行处理。
在处理过程中,将计算
该表达式的值。
(3) 若是其它字符,则返回错误信息。
3、若上述处理过程中没有发现错误,则认为该表达式合法,并打印
处理结果。
程序中应主要包含下面几个功能函数:
void initstack():初始化堆栈
int Make_str():语法检查并计算
int push_operate(int operate):将操作码压入堆栈
int push_num(double num):将操作数压入堆栈
int procede(int operate):处理操作码
int change_opnd(int operate):将字符型操作码转换成优先级
int push_opnd(int operate):将操作码压入堆栈
int pop_opnd():将操作码弹出堆栈
int caculate(int cur_opnd):简单计算+,-,*,/
double pop_num():弹出操作数
3.已知函数t(n)=2*t(n/2)+n 其中t(0)=0,n为整数。
编写程序实现:
(1) 计算t(n)的递归算法。
(2) 用链式栈实现计算t(n)的非递归算法。
四、思考与提高
1.如果一个程序中要用到两个栈,为了不发生上溢错误,就必须给每个栈预先分配一个足够大的存储空间。
若每个栈都预分配过大的存储空间,势必会造成系统空间紧张。
如何解决这个问题?
2.栈的两种存储结构在判别栈空与栈满时,所依据的条件有何不同?
3.在程序中同时使用两个以上的栈时,使用顺序栈共享邻接空间则很难实现,能否通过链栈来方便地实现?如何实现?
#include<stdio.h> #include<conio.h> #include<math.h> #include<stdlib.h>
typedef struct
{
char fun;
int grade;
}Functor;
//定义算符栈结构体
Functor FUNCTOR[20];
float NUM[20];
//定义算符栈和对象栈
char ch[100];
int sub=0;
//存放输入流的字符串
float Char_To_Num(){
//将表示数据的字符串转化成数据
int flag=0, i=-1;
float value=0.0;
while((ch[sub]>=48 && ch[sub]<=57) || ch[sub]=='.'){
if(ch[sub]=='.')
flag=1;
else{
if(flag==0) value=value*10+ch[sub]-48; else{
value=value+( ch[sub]-48 )*pow(10,i);
i--;
}}
sub++;
}
return value;
}
int In_Grade(char c)
{ //算符在栈内时的级别
int g;
switch(c)
{
case '^': g=3;break;
case '*':
case '/':
case '%': g=2;break;
case '+':
case '-': g=1;break;
case '(': g=0;break;
case ')': g=-1;break;
}
return g;
}
int Out_Grade()
{ //算符在栈外时的级别
int g;
switch(ch[sub])
{
case '^': g=4;break;
case '*':
case '/':
case '%': g=2;break;
case '+':
case '-': g=1;break;
case '(': g=4;break;
case ')': g=-1;break;
}
return g;
}
void Error()
{
printf("输入的表达式有误!\n");
printf("\n按任意键退出");
getch();
exit(1);
}
void Calculate(int i, int j)
{
if(i>=2)
{ //判断对象栈中元素个数
switch(FUNCTOR[j-1].fun)
{
case '^': NUM[i-2]=pow(NUM[i-2],NUM[i-1]); break;
case '*': NUM[i-2]=NUM[i-2]*NUM[i-1]; break; case '/': NUM[i-2]=NUM[i-2]/NUM[i-1]; break; case '%': NUM[i-2]=int(NUM[i-2])%int(NUM[i-1]); break;
case '+': NUM[i-2]=NUM[i-2]+NUM[i-1]; break; case '-': NUM[i-2]=NUM[i-2]-NUM[i-1]; break;
}
NUM[i-1]=0;
FUNCTOR[j-1].fun=0;
}
else Error();
//若对象栈若只剩一个数据,则输入的表达式有误
}
float Char_Transform(){
int i=0, j=0, grade, flag=0;
while( ch[sub]!='=' || j!=0 ){
if(ch[sub]=='='){
//输入的字符是否取完
Calculate(i, j);
i--;
j--;}
else{
if(ch[sub]>=48 && ch[sub]<=57){
//判断是否为运算对象
NUM[i++]=Char_To_Num();
if(flag){
NUM[i-1]=-NUM[i-1];
FUNCTOR[j-1].fun=0;
j--;
flag=0;
}}
else{
if(ch[sub]=='%' ||
(ch[sub]>=40 && ch[sub]<=43) ||
ch[sub]=='-' ||ch[sub]=='^' ||
ch[sub]=='/'){
//判断是否为算符
if( FUNCTOR[j-1].fun=='-' &&
FUNCTOR[j-2].fun=='(' &&
ch[sub]==')'){
//判断是否为负数
NUM[i-1]=-NUM[i-1];
FUNCTOR[j-1].fun=0;
FUNCTOR[j-2].fun=0;
j=j-2;
sub++;}
else{
if( FUNCTOR[j-1].fun== '(' && ch[sub]== ')' ){
//括号内表达式计算完后则将左括号从栈中去除
FUNCTOR[j-1].fun=0;
j--;
sub++;}
else{
grade=Out_Grade(); //栈外算符的级别
if(j==0 || grade>FUNCTOR[j-1].grade){
//第一个或级别比栈内算符高的进栈
FUNCTOR[j].fun=ch[sub];
FUNCTOR[j].grade=In_Grade(ch[sub]);
if(j==0 && FUNCTOR[j].fun=='-') flag=1;
j++;
sub++;}
else{
Calculate(i, j);
i--;
j--;
}}}}
else Error();
//表达式中有非算术字符,则表达式有误
}}}
return NUM[i-1];
}
void main()
{
float result;
printf("****************************************\n"); printf("请输入要求解的表达式,并以等号“=”结束:\n"); printf("****************************************\n"); gets(ch);
result=Char_Transform();
printf("%s%.2f\n", ch, result);
printf("\n按任意键退出");
getch();
}
实验3: 队列的操作实验一、实验目的
1.熟悉并能实现顺序循环队列的定义和基本操作。
2.了解用队列解决实际应用问题。
二、实验要求
1.进行队列的基本操作时要注意队列“先进先出”的特性。
2.复习关于栈操作的基础知识。
3.编写完整程序完成下面的实验内容并上机运行。
三、实验内容
1.任意输入队列长度和队列中的元素值,构造一个顺序循环队列,对其进行清空、插入新元素、返回队头元素以及删除队头元素操作。
2.约瑟夫环的实现:设有n个人围坐在圆桌周围,现从某个位置i 上的人开始报数,数到m 的人就站出来。
下一个人,即原来的第m+1个位置上的人,又从1开始报数,再是数到m的人站出来。
依次重复下去,直到全部的人都站出来,按出列的先后又可得到一个新的序列。
由于该问题是由古罗马著名的史学家Josephus提出的问题演变而来,所以通常称为
Josephus 问题。
例如:当n=8,m=4,i=1时,得到的新序列为:
4,8,5,2,1,3,7,6
编写程序选择循环队列作为存储结构模拟整个过程,并依次输出出列的各人的编号。
四、思考与提高
1.链栈只有一个top指针,对于链队列,为什么要设计一个头指针和一个尾指针?
2.一个程序中如果要用到两个栈时,可通过两个栈共享一维数组来实现。
即双向栈共享邻接空间。
如果一个程序中要用到两个队列,能否实现?
如何实现?
#include "stdio.h" #include "malloc.h" #include "stdlib.h" #include "conio.h" #define MAX 80 typedef struct
{
int data[MAX];
int front,rear;
int num;
}SeQue;
SeQue *Init_SeQue()
{
SeQue *s;
s=new SeQue;
s->front=s->rear=MAX-1;
s->num=0;
return s;
}
int Empty_SeQue(SeQue *s)
{
if(s->num==0)
return 1;
else
return 0;
}
int In_SeQue(SeQue *s,int x)
{
if(s->num==MAX)
return 0;
else
{
s->rear=(s->rear+1)%MAX;
s->data[s->rear]=x;
s->num++;
return 1;
}
}
int Out_SeQue(SeQue *s,int *x) {
if(Empty_SeQue(s))
return 0;
else
{
s->front=(s->front+1)%MAX;
*x=s->data[s->front];
s->num--;
return 1;
}
} void Print_SeQue(SeQue *s)
{
int i,n;
i=(s->front+1)%MAX;
n=s->num;
while(n>0)
{ printf("%d ",s->data[i]);
i=(i+1)%MAX;
n--;
}
}
void main()
{
SeQue *s;
int k,flag,x;
s=Init_SeQue();
do{
printf("\n\n\n");
printf("\t\t\t 循环顺序队列\n");
printf("\t\t\t***********************\n");
printf("\t\t\t** 1-入队**\n");
printf("\t\t\t** 2-出队**\n");
printf("\t\t\t** 3-判队空**\n");
printf("\t\t\t** 4-队列显示**\n");
printf("\t\t\t** 0-返回**\n");
printf("\t\t\t***********************\n");
printf("\t\t\t 请输入菜单项(0-4):");
scanf("%d",&k);
switch(k)
{
case 1:
printf("\n请输入入队元素:");
scanf("%d",&x);
flag=In_SeQue(s,x);
if(flag==0)
printf("\n队满不能入队!按任意键返回..");
else
printf("\n元素已入队!按任意键返回..");
getch();
system("cls");
break;
case 2:
flag=Out_SeQue(s,&x);
if(flag==0)
printf("\n队列空出队失败!按任意键返回..");
else
printf("\n队列头元素已出队~!按任意键返回..");
getch();
system("cls");
break;
case 3:
flag=Empty_SeQue(s);
if(flag==1)
printf("\n该队列为空!按任意键返回..");
else
printf("\n该队列不为空!按任意键返回..");
getch();
system("cls");
break;
case 4:
printf("\n该队列元素为:");
Print_SeQue(s);
printf("\n按任意键返回..");
getch();
system("cls");
break;
}
}while(k!=0);
}
实验4:二叉树实验一、实验目的
1.学会实现二叉树结点结构和对二叉树的基本操作。
2.掌握对二叉树每种操作的具体实现,学会利用递归方法编写对二叉树这种递归数据结构进行处理的算法。
二、实验要求
1.认真阅读和掌握和本实验相关的教材内容。
2.编写完整程序完成下面的实验内容并上机运行。
三、实验内容
1.编写程序任意输入二叉树的结点个数和结点值,构造一棵二叉树,采用三种递归遍历算法(前序、中序、后序)对这棵二叉树进行遍历并计算出二叉树的高度。
2.编写程序生成下面所示的二叉树,并采用中序遍历的非递归算法对此二叉树进行遍历。
四、思考与提高
1.如何计算二叉链表存储的二叉树中度数为1的结点数?
2.已知有—棵以二叉链表存储的二叉树,root指向根结点,p指向二叉树中任一结点,如何求从根结点到p所指结点之间的路径?
#include<iostream> #include<string>
#include<stack> using namespace std; int main() {
string s; string result;
stack<char> mystack;
char tmp;
cin >> s;
for (int i = 0; i < s.length(); i ++)
switch (s[i])
{
case '+':
case '-':
while (!mystack.empty())
{
tmp = mystack.top();
if (tmp != '(')
{
result += tmp;
mystack.pop();
}
else break;
}
mystack.push(s[i]);
break;
case '*':
case '/':
while (!mystack.empty())
{
tmp = mystack.top();
if (tmp != '(' && tmp != '+' && tmp != '-') {
result += tmp;
mystack.pop();
}
else break;
}
mystack.push(s[i]);
break;
case '(':
mystack.push(s[i]);
break;
case ')':
while (!mystack.empty())
{
tmp = mystack.top();
mystack.pop();
if (tmp != '(')
result += tmp;
else break;
}
break;
default:
result += s[i];
}
while (!mystack.empty())
{
tmp = mystack.top(); mystack.pop();
result += tmp;
}
cout << result << endl;
return 0;
}
#include<iostream>
#include<string>
#include<stack>
using namespace std;
struct node
{
string data;
node * leftchild;
node * rightchild;
};
node * buildtree(string str, int l, int r) {
node * root = new node;
int i, k = 0;
if (str[l] == '(' && str[r] == ')')
{
for (i = l; i <= r - 1; i ++)
{
if (str[i] == '(') k ++;
if (str[i] == ')') k --;
if (k == 0) break;
}
if (i == r)
l ++, r --;
}
k = 0;
for (i = r; i >= l; i --)
{
if (str[i] == ')') k ++;
if (str[i] == '(') k --;
if ((str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/') && k == 0)
break;
}
if (i == l - 1)
{
root -> data = str.substr(l, r - l + 1);
root -> leftchild = root -> rightchild = NULL; }
else
{
root -> data = str[i];
root -> leftchild = buildtree(str, l, i - 1);
root -> rightchild = buildtree(str, i + 1, r);
}
return root;
}
void printqianzhui(node * root)
{
if (root == NULL) return;
cout << root -> data << ' '; printqianzhui(root -> leftchild); printqianzhui(root -> rightchild);
}
void printhouzhui(node * root)
{
if (root == NULL) return;
printhouzhui(root -> leftchild); printhouzhui(root -> rightchild);
cout << root -> data << ' ';
}
int main()
{
string str;
cin >> str;
node * root = buildtree(str, 0, str.length() - 1);
printqianzhui(root);
cout << endl;
printhouzhui(root);
cout << endl;
return 0;
}
实验5:内部排序实验
一、实验目的
1.掌握简单插入排序、冒泡排序、快速排序、堆排序以及归并排序的算法并加以应用。
2.对各种查找、排序技术的时间、空间复杂性有进一步认识。
二、实验要求
1.认真阅读和掌握和本实验相关的教材内容。
2.编写完整程序完成下面的实验内容并上机运行。
3.整理并上交实验报告。
三、实验内容
编写程序实现下述五种算法,并用以下无序序列加以验证:
49,38,65,97,76,13,27,49
1.简单插入排序
2.冒泡排序
3.快速排序
4.归并排序
5.堆排序
四、思考与提高
1.设有1000个无序的元素,希望用最快的速度挑出其中前10个最大的元素,采用哪一种排序方法最好?为什么?
2.如何构造一种排序方法,使五个整数至多用七次比较就可以完成排序任务?
快速排序
void Quick_Sort(int list[ ], int left, int right) //lfet = 0, right = MAX
{
int s;
int i, j;
int temp;
if(left < right)
{
s = list[left];
i = left-1;
j = right + 1;
while(i+1!=j) {
if(list[i+1]<=s)
i++;
else if(list[j-1]>s)
j--;
else {
temp=list[i+1];
list[++i]=list[j-1];
list[--j]=temp;
}
}
list[left] = list[i];
list[i] = s;
Quick_Sort(list, left, i - 1); //对左边递归Quick_Sort(list, i + 1, right); //对右边递归
}
}。