数据结构实验报告

这篇实验报告详细介绍了数据结构的多个实验,包括线性表实现约瑟夫问题,栈和队列用于表达式求值,数组在稀疏矩阵转置中的应用,二叉树遍历和深度计算,图的深度优先搜索和最小生成树构造,以及排序算法的实现和效率分析。每个实验都包含了目的、内容、程序清单、测试结果和算法分析。

可以先看看,如果需要的话,可以在网盘下载:

链接:https://pan.baidu.com/s/1nvSk3wd 密码:q6dm

优快云资源地址:https://download.youkuaiyun.com/download/eseszb/10502914




《数据结构》实验指导书

实验描述 

实验一  线性表的应用

【实验目的】
1. 熟练掌握线性表的基本操作在顺序存储和链式存储上的实现;
2. 以线性表的各种操作(建立、插入、删除、遍历等)的实现为重点;
3. 掌握线性表的动态分配顺序存储结构的定义和基本操作的实现;
4. 通过本章实验帮助学生加深对C语言的使用(特别是函数的参数调用、指针类型的应用和链表的建立等各种基本操作)。

【实验内容】
约瑟夫问题的实现:n只猴子要选猴王,所有猴子按1,2,…,n编号围坐一圈,从第1只开始按1,2,…,m报数,凡报到m号的猴子退出圈外,如此循环报数,直到圈内剩下一只猴子时,这个猴子就是猴王。编写一个程序实现上述过程,n和m由键盘输入。

【实验要求】
1. 要求用顺序表和链表分别实现约瑟夫问题;
2. 独立完成,严禁抄袭;
3. 上交的实验报告由如下部分组成:①实验名称②实验目的③实验内容(数据描述,算法描述,程序清单,测试结果,算法分析) 

 

实验二  栈和队列的应用

【实验目的】
1. 熟练掌握栈和队列的结构,以及这两种数据结构的特点;

2. 能够在两种存储结构上实现栈的基本运算,特别注意栈满栈空的判断条件和描述方法;

3. 熟练掌握链队列和循环队列的基本运算,特别注意队列满和队列空的判断条件和描述方法。

【实验内容】
表达式求值的实现:输入一个包含“+”、“-”、“*”、“/”、正整数和圆括号的合法表达式,用算符优先法计算该表达式的结果。

【实验要求】
1. 要求用栈实现表达式求值问题;
2. 独立完成,严禁抄袭;
3. 上交的实验报告由如下部分组成:①实验名称②实验目的③实验内容(数据描述,算法描述,程序清单,测试结果,算法分析) 

 

实验三  数组的应用

【实验目的】
1. 掌握数组的两种存储表示方法;
2. 掌握对特殊矩阵进行压缩存储时的下标变换公式;
3. 掌握稀疏矩阵的两种压缩存储方法的特点和适用范围。

【实验内容】
稀疏矩阵转置的实现:用三元组顺序表做存储结构,实现稀疏矩阵的转置。

【实验要求】
上交实验报告,要求同上。 

实验四  树和二叉树的应用

【实验目的】
1. 熟练掌握树的基本概念、二叉树的基本操作及在链式存储结构上的实现;

2. 重点掌握二叉树的生成、遍历及求深度等算法;

3. 掌握哈夫曼树的含义及其应用。

4. 掌握运用递归方式描述算法及编写递归C程序的方法,提高算法分析和程序设计能力。

【实验内容】
二叉树采用二叉链表作存储结构,试编程实现二叉树的如下基本操作:
1. 按先序序列构造一棵二叉链表表示的二叉树T;
2. 对这棵二叉树进行遍历:中序、后序以及层次遍历序列,分别输出结点的遍历序列;
3. 求二叉树的深度/叶结点数目。

【实验要求】
上交实验报告,要求同上。 

 

实验五  图的应用

【实验目的】
1. 熟练掌握图的邻接矩阵和邻接表的存储方式;

2. 实现图的一些基本运算,特别是深度遍历和广度遍历;

3. 掌握以图为基础的一些常用算法,如最小生成树、拓扑排序、最短路径等。

 

【实验内容】
1. 由给定的顶点和边的信息构造图的邻接矩阵存储; 对该图进行深度优先搜索,输出搜索得到的结点序列;

 


3. 以邻接表作存储结构,用克鲁斯卡尔算法构造最小生成树。

 

【实验要求】
上交实验报告,要求同上。

 

实验六  查找表的应用

【实验目的】
1. 熟练掌握静态查找表的构造方法和查找算法;

2. 熟练掌握二叉排序树的构造和查找方法;

3. 熟练掌握哈希表的构造和处理冲突的方法;

4. 掌握各种查找表查找效率的分析方法。

 

【实验内容】
1. 要求将二叉排序树的建立、插入、删除、显示等算法合并在一个综合程序中,用户可通过菜单选择方式运行各种操作算法;
2. 已知哈希表的表长为m,哈希函数为H(key)=keyMOD p,用开放定址法(增量序列采用线性探测再散列)解决冲突,试编写构造哈希表的程序。

 

【实验要求】
上交实验报告,要求同上。 

 

 

实验七 排序算法的应用

【实验目的】
1. 熟练掌握各种排序的算法思想、方法及稳定性;

2. 对一组数据,能写出其具体的排序过程、算法及完整程序,并上机调试;

3. 掌握每一种排序算法的时空复杂度的分析方法。

 

【实验内容】
有如下数据:

成绩   75    87   68    92    88   61    77    96   80    72

姓名  王华 李燕  张萍  陈涛 刘丽  章强  孙军 朱彬  徐伟  曾亚

以成绩作关键字,试编程实现如下基本操作:

1. 用冒泡排序对上面数据按成绩非递减排列,并分析时空复杂度;

2. 用简单选择排序对上面数据按成绩非递减排列,并分析时空复杂度;

3. 用快速排序对上面数据按成绩非递减排列,并分析时空复杂度。

 

【实验要求】

上交实验报告,要求同上。 


实验报告如下:

实验报告

 

实验一

一、实验名称:线性表的应用

二、实验目的:

1. 熟练掌握线性表的基本操作在顺序存储和链式存储上的实现;
2. 以线性表的各种操作(建立、插入、删除、遍历等)的实现为重点;
3. 掌握线性表的动态分配顺序存储结构的定义和基本操作的实现;
4. 通过本章实验帮助学生加深对C语言的使用(特别是函数的参数调用、指针类型的应用和链表的建立等各种基本操作)。

三、实验内容:

约瑟夫问题的实现:n只猴子要选猴王,所有猴子按1,2,…,n编号围坐一圈,从第1只开始按1,2,…,m报数,凡报到m号的猴子退出圈外,如此循环报数,直到圈内剩下一只猴子时,这个猴子就是猴王。编写一个程序实现上述过程,n和m由键盘输入。

四、程序清单:

顺序表实现:

#include"stdio.h"

int main()
{
    int count,num,i;
    int a[1010],n,m;
    while(scanf("%d%d",&n,&m)==2)
   {
       count=0;
       num=n;         //记录未退出的猴子数
       for(i=1;i<=n;i++)
       {
              a[i]=1;    //每个猴子标记为1,表示该猴子未退出
          }
       while(num!=1)  //当只有一猴子时,退出循环
       {
          for(i=1;i<=n;i++)
          {
                 if(a[i]==1)
                 {
                   count++;
                }
              if(count==m)
              {
                a[i]=0;  //
                num--;   //退出一只猴子
                 count=0;
              }
          }
          }
       for(i=1;i<=n;i++)
       {
          if(a[i]==1)     //输出最后剩下的那只猴子,猴王
          {
              printf("%d\n",i);
              break;
          }
       }
   }
    return 0;
}


 

链表实现:

#include <iostream>
#include <stdio.h>
using namespace std;
 
struct node{
   int data;
   int last;
   int next;
};
 
struct node a[100];
 
int main(int argc, char**argv) {
   int n,m;
   while(scanf("%d%d",&n,&m)==2)
   {
       for(int i=2;i<n;i++)
       {
          a[i].data=i; a[i].last=i-1;  a[i].next=i+1;
       }
       a[1].data=1; a[1].last=n;  a[1].next=2;
       a[n].data=n; a[n].last=n-1; a[n].next=1;
      
       int num=1;       //记录报数次数
       int count=1;     //记录当前猴子的序号
       while(a[count].next!=a[count].data)
       {
          if(num%m==0)
          {
              a[a[count].last].next=a[count].next;
              a[a[count].next].last=a[count].last;
          }
          num++;
          count=a[count].next;
       }
       printf("%d\n",a[count].data);
   }
  
   return 0;
}


 

五、测试结果:

六、算法分析:

顺序表实现:

时间复杂度:

该代码主要耗时取决于while(num!=1)里的内容

T(n)=O(n^2)

空间复杂度:

S(n)=O(n^2)

链表实现:

时间复杂度:

该代码主要耗时取决于while(a[count].next!=a[count].data)里的内容

T(n)=O(n)

空间复杂度:S(n)=O(n)

 

 

 

实验二

一、实验名称:栈和队列的应用

二、实验目的:

1. 熟练掌握栈和队列的结构,以及这两种数据结构的特点;

2. 能够在两种存储结构上实现栈的基本运算,特别注意栈满栈空的判断条件和描述方法;

3. 熟练掌握链队列和循环队列的基本运算,特别注意队列满和队列空的判断条件和描述方法。

三、实验内容:

表达式求值的实现:输入一个包含“+”、“-”、“*”、“/”、正整数和圆括号的合法表达式,用算符优先法计算该表达式的结果。

四、程序清单:

/*

本代码的输入为表达式,以‘#’结尾

例如:2+3*(33-23)+5/4#*/

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <stack>
#include <stdlib.h>
using namespace std;

char ch[10]={'+','-','*','/','(',')','#'};

int compare[7][7]={       //优先级数组
	1,1,-1,-1,-1,1,1,
	1,1,-1,-1,-1,1,1,
	1,1,1,1,-1,1,1,
	1,1,1,1,-1,1,1,
	-1,-1,-1,-1,-1,0,1,
	1,1,1,1,1,1,1,
	-1,-1,-1,-1,-1,1,0
};

int precede(char a,char b)  //比较a和b两个运算符的有优先级
{
	int x,y;
	for(int i=0;i<7;i++)
	{
		if(ch[i]==a) x=i;
		if(ch[i]==b) y=i;
	}
	return compare[x][y];
}

int number(char a[],int sum)  //字符串转实数
{
	int ans=0;
	for(int i=0;i<sum;i++)
	{
		ans+=(a[i]-'0')*pow(10,sum-i-1);
	}
	return ans;
}

int in(char c)                //判断当前运算符是否合法
{
	if(c=='+' || c=='-' || c=='*' || c=='/' || c=='(' || c==')' || c=='#') return 1;
	else  return 0;
}

double operate(double a,char theta,double b)  //四则运算
{
	if(theta=='*') return a*b;
	else if(theta=='/') return a/b;
	else if(theta=='+') return a+b;
	else if(theta=='-') return a-b;
}

int main(int argc, char *argv[]) {
	char s[100],mid[100],c;
	stack<char> optr;  optr.push('#');
	stack<double> opnd;
	scanf("%s",s);
	int count=0;
	c=s[count];
	while(c!='#' || optr.top()!='#')
	{
		if(c-'0'>=0 && c-'0'<=9)
		{
			int coun=0;
			while(c-'0'>=0 && c-'0'<=9)
			{
				mid[coun++]=c;   c=s[++count];
			}
			double num=number(mid,coun);
			opnd.push(num);
		}
		else if(in(c))
		{
			switch(precede(optr.top(),c))
			{
				case -1:
				{
					optr.push(c);  c=s[++count];
					break;
				}
				case 0:
				{
					optr.pop();  c=s[++count];
					break;
				}
				case 1:
				{
					char theta=optr.top();  optr.pop();
					double b=opnd.top();    opnd.pop();
					double a=opnd.top();    opnd.pop();
					opnd.push(operate(a,theta,b));
					break;
				}
			}
		}
	}
	printf("%lf\n",opnd.top());
	return 0;
}


五、测试结果:

六、算法分析:

算符优先法求表达式的值,一个字符栈存运算符,一个实数栈存数据,根据算符优先级作相应操作


实验三

一、实验名称:数组的应用

二、实验目的:

1.掌握数组的两种存储表示方法;
2. 掌握对特殊矩阵进行压缩存储时的下标变换公式;
3. 掌握稀疏矩阵的两种压缩存储方法的特点和适用范围。

三、实验内容:

稀疏矩阵转置的实现:用三元组顺序表做存储结构,实现稀疏矩阵的转置。

四、程序清单:

/*

8

1 2 12

1 3 9

3 1 -3

3 6 14

4 3 24

5 2 18

6 1 15

6 4 -7

*/

#include <iostream>
#include <stdio.h>
using namespace std;

#define maxn 100

struct{            //定义三元顺序表
	int row,col;
	int data;
}m[maxn],t[maxn];

int num[maxn],cpot[maxn];  //矩阵m中,第i行非零元个数   第i列第一个非零元在t中的恰当位置

int main(int argc, char** argv) {

	int sum;             //元素个数
	int max_col=-1;      //矩阵M的列数

	printf("请输入元素个数:\n");
	scanf("%d",&sum);


	printf("转置前:\n");
	for(int i=1;i<=sum;i++)
	{
		scanf("%d %d %d",&m[i].row,&m[i].col,&m[i].data);
		if(m[i].col>max_col) max_col=m[i].col;
	}
	printf("\n");

    for(int i=1;i<=max_col;i++)  num[i]=0;
    for(int i=1;i<=sum;i++)  ++num[m[i].col];

    cpot[1]=1;
    for(int i=2;i<=max_col;i++) cpot[i]=cpot[i-1]+num[i-1];

	for(int i=1;i<=sum;i++)
    {
        int cur=m[i].col;
        int j=cpot[cur];
        t[j].row=m[i].col;  t[j].col=m[i].row;  t[j].data=m[i].data;
        ++cpot[cur];
    }

	printf("转置后:\n");
	for(int i=1;i<=sum;i++)
		printf("%d %d %d\n",t[i].row,t[i].col,t[i].data);
	return 0;
}


五、测试结果:

六、算法分析:

三元组顺序表做存储结构,定义两个三元组顺序表,一个作为中间变量

时间复杂度为O(sum+max_col)



实验四

一、实验名称:数和二叉树的应用

二、实验目的:

1. 熟练掌握树的基本概念、二叉树的基本操作及在链式存储结构上的实现;

2. 重点掌握二叉树的生成、遍历及求深度等算法;

3. 掌握哈夫曼树的含义及其应用。

4. 掌握运用递归方式描述算法及编写递归C程序的方法,提高算法分析和程序设计能力。

三、实验内容:=

二叉树采用二叉链表作存储结构,试编程实现二叉树的如下基本操作:
1. 按先序序列构造一棵二叉链表表示的二叉树T;
2. 对这棵二叉树进行遍历:中序、后序以及层次遍历序列,分别输出结点的遍历序列;
3. 求二叉树的深度/叶结点数目。

四、程序清单:

/*

输入二叉树的先序序列

例如:"abc  de g  f   "

             ---------------

abc两个空格de空格g两个空格f三个空格

*/

 

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <stack>
using namespace std;

#define OVERFLOW -2
#define STACK_INIT_SIZE 50
#define STACKINTCREMENT 10
typedef struct BiTNode
{
    char data;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

int CreateBiTree(BiTree &t)
{
    char ch;
    scanf("%c",&ch);
    if(ch==' ') t=NULL;
    else
    {
        if(!(t=(BiTNode*)malloc(sizeof(BiTNode))))
            exit(OVERFLOW);
        t->data=ch;
        CreateBiTree(t->lchild);
        CreateBiTree(t->rchild);
    }
    return 0;
}

int InOrderTraverse(BiTree t)
{
    if(t)
    {
        InOrderTraverse(t->lchild);
        printf("%c",t->data);
        InOrderTraverse(t->rchild);
    }
    return 0;
}

int PostorderTraverse(BiTree t)
{
    if(t)
    {
        PostorderTraverse(t->lchild);
        PostorderTraverse(t->rchild);
        printf("%c",t->data);
    }
    return 0;
}

queue <BiTNode*> que;

void bfs(BiTree t)
{
    if(t)
    {
        que.push(t);
        while(!que.empty())
        {
            BiTree c=que.front();
            que.pop();
            printf("%c",c->data);
            if(c->lchild && c->data) que.push(c->lchild);
            if(c->rchild && c->data) que.push(c->rchild);
        }
    }
    printf("\n");
}

int main()
{
    BiTree t;
    printf("请输入二叉树的先序序列\n");
    CreateBiTree(t);
    printf("二叉树的中序序列\n");
    InOrderTraverse(t);
    printf("\n");
    printf("二叉树的后序序列\n");
    PostorderTraverse(t);
    printf("\n");
    printf("二叉树的层次遍历序列\n");
    bfs(t);
    printf("\n");
    return 0;
}


五、测试结果:

六、算法分析:

时间复杂度T(n)=O(n)

n为节点数



实验五

一、实验名称:图的应用

二、实验目的:

1. 熟练掌握图的邻接矩阵和邻接表的存储方式;

2. 实现图的一些基本运算,特别是深度遍历和广度遍历;

3. 掌握以图为基础的一些常用算法,如最小生成树、拓扑排序、最短路径等。

三、实验内容:

1. 由给定的顶点和边的信息构造图的邻接矩阵存储; 对该图进行深度优先搜索,输出搜索得到的结点序列;


3. 以邻接表作存储结构,用克鲁斯卡尔算法构造最小生成树。

四、程序清单:

/*

5 6

abcde

0 1 10

0 3 20

1 2 30

1 4 40

2 3 50

2 4 60

*/

 

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
#define maxn 100
#define INF 999999
#define MAXVEX 100
typedef struct {
    char vexs[MAXVEX];
    double arcs[MAXVEX][MAXVEX];
    int n,e;
}mGraph;

queue<char> qu;
int flag[maxn];

void createAdjMatrix(mGraph *G)
{
    int i,j,k;
    double w;
    printf("请输入图的节点数和边数:\n");
    scanf("%d%d",&G->n,&G->e);
    getchar();
    for(i=0;i<G->n;i++) flag[i]=0;
    printf("请输入图的节点:\n");
    for(k=0;k<G->n;k++) scanf("%c",&G->vexs[k]);
    for(i=0;i<G->n;i++)
        for(j=0;j<G->n;j++)
            G->arcs[i][j]=INF;
    printf("请输入图的边以及边的权:\n");
    for(k=0;k<G->e;k++)
    {
        scanf("%d%d%lf",&i,&j,&w);
        G->arcs[i][j]=w;
        G->arcs[j][i]=w;
    }
}

void bfs(mGraph *G)
{
    int num=0;
    for(int i=0;i<G->n;i++) flag[i]=0;
    for(int i=0; i<G->n; i++)
        if(flag[i]==0)
        {
            flag[i]=1;
            qu.push(G->vexs[i]);
            while(!qu.empty())
            {
                char ss=qu.front();
                qu.pop();
                if(num==G->n-1)
                    cout<<ss<<endl;
                else
                    cout<<ss<<" ";
                num++;
                for(int j=0; j<G->n; j++)
                    if(G->arcs[i][j]<INF && flag[j]==0)
                    {
                            qu.push(G->vexs[j]); flag[j]=1;
                    }
            }
        }
}

int main()
{
    mGraph m;
    createAdjMatrix(&m);
    printf("遍历序列如下:\n");
    bfs(&m);
    return 0;
}


五、测试结果:

六、算法分析:

时间复杂度T(n)= O(n^2)+O(e)

n节点数,    e为边数




实验七

一、实验名称:排序算法的应用

二、实验目的:

1.熟练掌握各种排序的算法思想、方法及稳定性;

2.对一组数据,能写出其具体的排序过程、算法及完整程序,并上机调试;

3. 掌握每一种排序算法的时空复杂度的分析方法。

 

三、实验内容:

有如下数据:

成绩   75    87   68    92    88   61    77    96   80    72

姓名  王华  李燕  张萍  陈涛  刘丽  章强  孙军  朱彬  徐伟  曾亚

以成绩作关键字,试编程实现如下基本操作:

1. 用冒泡排序对上面数据按成绩非递减排列,并分析时空复杂度;

2. 用简单选择排序对上面数据按成绩非递减排列,并分析时空复杂度;

3. 用快速排序对上面数据按成绩非递减排列,并分析时空复杂度。

四、程序清单:

#include <iostream>
#include "stdio.h"
#include "algorithm"
using namespace std;

#define maxn 10

struct Student{
	int grade;
	char name[maxn];
};

struct Student student[maxn]={
								{75,"王华"},{87,"李燕"},{68,"张萍"},{92,"陈涛"},{88,"刘丽"},
								{61,"章强"},{77,"孙军"},{96,"朱彬"},{80,"徐伟"},{72,"曾亚"}
};

bool cmp(Student a,Student b)
{
	return a.grade<=b.grade;
}

void print(int n)			//打印结果
{
	for(int i=0;i<n;i++)
	{
		printf("%d %s\n",student[i].grade,student[i].name);
	}
}

int main(int argc, char** argv) {

	/*
	for(int i=0;i<maxn-1;i++)								//冒泡排序
		for(int j=0;j<maxn-i-1;j++)
			if(student[j].grade>=student[j+1].grade)
			{
				struct Student temp=student[j];
				student[j]=student[j+1];
				student[j+1]=temp;
			}
	*/

/*
	for(int i=0;i<maxn-1;i++)//选择排序
    {
        int minn=student[i].grade;
        int cur=i;
        for(int j=i+1;j<maxn;j++)
        {
            if(student[j].grade<minn)
            {
                minn=student[j].grade;
                cur=j;
            }
        }
        if(i!=cur)
        {
            struct Student temp=student[i];
            student[i]=student[cur];
            student[cur]=temp;
        }

}
*/

	sort(student,student+maxn,cmp);							//快速排序
	print(10);
	return 0;
}


五、测试结果:

六、算法分析:

冒泡排序:时间复杂度T(n)=O(n^2)

选择排序:时间复杂度T(n)=O(n^2)

快速排序:时间复杂度T(n)=O(n*log(n))

 



实验六是查找表的应用,因为博主有事没上这个章节的课,所以没写,多多包涵啊!!!


评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值