《数据结构与算法设计》实验报告书之字符串和数组的基本操作
实验项目
字符串和数组的基本操作
实验目的
1.掌握数组的定义
2.理解求稀疏矩阵的转置矩阵算法在三元组表示上的实现。
实验内容
1.利用C语言实现数组的定义。
2.实现稀疏矩阵的三元组表示以及转置算法。
算法设计分析
(一)数据结构的定义
有时候我们的矩阵中只有零星的一些非零元素,其余的都是零元素,那么我们称之为稀疏矩阵,当然没有绝对的说有多少个零元素才算稀疏。简单说,稀疏矩阵就是非零元素个数远远小于元素个数的矩阵。相对于稀疏矩阵来说,一个不稀疏的矩阵也称作稠密矩阵。针对上面的这个无规律的存放非零元素,三元组提出了一种方法,就是仅仅记录矩阵中的非零元素以及它的行,列以及值N(x,y,v)构成的一个三元组,标识一个稀疏矩阵的话,还要记录该矩阵的阶数,这样我们就将一个二维的变成了一个一维,极大的压缩的存储空间。 这里要注意的就是,三元组的构建采用“行”是从上到下,“列”也是从左到右的方式构建的顺序表。
顺序表存储结构定义为:
/*定义稀疏矩阵三元组*/
#define MAXSIZE 12500
typedef struct {
int i, j; //该非零元的行列下标
int e;
}Triple;
typedef struct {
Triple data[MAXSIZE];
int mu, nu, tu;
//矩阵的行、列数和非零元个数
}TSMatrix;
(二)总体设计
实验总共包括五个函数:主函数,初始化稀疏矩阵三元组函数,打印稀疏矩阵三元组函数,转置稀疏矩阵三元组函数,快速转置稀疏矩阵三元组函数。
主函数:统筹调用各个函数以实现相应功能
Int main()
Void opration()
初始化稀疏矩阵三元组函数:建立初始化稀疏矩阵三元组
Void init ()
打印稀疏矩阵三元组函数:打印稀疏矩阵三元组构成的稀疏矩阵
Int Print()
转置稀疏矩阵三元组函数:利用普通方法遍历转置稀疏矩阵
Void exchange()
快速转置稀疏矩阵三元组函数:利用快速方法直接转置稀疏矩阵
Void quickly ()
(三)各函数的详细设计:
主函数main()
主要就是进行功能的实现。
初始化稀疏矩阵三元组函数init():
建立初始化稀疏矩阵三元组,初始行,列,值的个数,再一一存入数据。
打印稀疏矩阵三元组函数Print()
将稀疏矩阵三元组构成的稀疏矩阵以数组的方式打印出来。
转置稀疏矩阵三元组函数exchange()
利用普通方法遍历转置稀疏矩阵,两层循环直接嵌套遍历整个二维数组,复杂度较高,效率不大。
快速转置稀疏矩阵三元组函数quickly()
利用快速方法遍历转置稀疏矩阵,直接使用一层循环,再遍历数据的同时把位置记下来,在其中找的时候直接把值放在了指定的位置,比起普通的方法快了很多。
实验测试结果
实验总结:(100字到200字)
(1)调试过程中主要遇到哪些问题?是如何解决的?
答:稀疏矩阵三元组的难度有点大,遇见的问题有一些。
1.在一开始打印时遇见数据打印不出来的问题,结果发现是由于初始化函数传值时没有使用&符号,导致三元组的数没有传入。
2.在进行普通转置函数的时候,没有想到需要用两个三元组来存放数据,导致走了很多的歪路,后来发现,有另一个三元组来存放数据比较方便快捷。
3.在快速转置的函数中,有些地方的逻辑还是不怎么清楚,需要加深理解,尤其是找位置的数组是如何来的。
(2)经验和体会
答:还是那句老话,多敲代码自己练习,有时间把多复习多看看书,增加自己对快速转置的理解能力。
附录 实验程序代码(该部分请加注释)
/SeqList.h函数代码/
//#ifndef SEQLIST_H_INCLUDED
//#define SEQLIST_H_INCLUDED
#define MAXSIZE 12500
typedef struct {
int i, j; //该非零元的行列下标
int e; //该元素的值
}Triple;
typedef struct {
Triple data[MAXSIZE];
int mu, nu, tu;
//矩阵的行、列数和非零元个数
}TSMatrix;
void init(TSMatrix &s)
{
int i;
std::cout<<"请输入需要打的行,列,值!!"<<std::endl;
std::cin>>s.mu>>s.nu>>s.tu; //输入每个值得位置以及值
for(i=0;i<s.tu;i++){//循环输入
std::cout<<"请输入第"<<i+1<<"的行号,列号,值:"<<std::endl;
std::cin>>s.data[i].i>>s.data[i].j>>s.data[i].e;
}
}
void Print(TSMatrix t)//打印函数
{
int time=0,i,j;
for(i=0;i<t.mu;i++)
for(j=0;j<t.nu;j++)
{
if(t.data[time].i==i&&t.data[time].j==j)//压缩矩阵不断输出
{
std::cout<<t.data[time].e;
time++;
}
else
std::cout<<"0";
if(j!=t.nu-1)//格式控制
std::cout<<" ";
else
std::cout<<std::endl;
}
}
void exchange(TSMatrix s,TSMatrix &t){//普通转置函数
t.mu=s.nu; t.nu=s.mu; t.tu=s.tu;//直接交换两个三元组得行数和列数
if (t.tu)//如果值的个数不为零就进入程序
{
int q = 0;//第二个三元组的下标
for (int col = 0; col < s.nu; col++){//按照顺序来循环找值
for (int p = 0; p < s.tu; p++){//遍历每个数据
if ( s.data[p].j == col )//如果对应的位置有值,则进入下面语句
{
t.data[q].i = s.data[p].j ;//交换行和列
t.data[q].j = s.data[p].i ;
t.data[q].e = s.data[p].e;//赋值
++ q;//下标加加
}
}
}
}
}
void quickly(TSMatrix M,TSMatrix &T)//快速转置函数
{
int num[200],cpot[200],q,col,t,p;//定义两个数组,第一个用来统计相同列的个数,另一个用来求位置。
T.mu = M.nu; T.nu = M.mu; T.tu = M.tu;//交换
if (T.tu) {
for ( col=0; col<M.nu; ++col)
num[col] = 0;//初始化
for ( t=0; t<M.tu; ++t)
num[M.data[t].j]++;//统计相同列的个数
// 求 M 中各列非零元的个数
cpot[0] = 0;
for ( col=1;col<M.nu;col++)
cpot[col] = cpot[col -1] + num[col -1];//求位置
for ( p=0; p<M.tu; ++p) { // 转置矩阵元素
col = M.data[p].j;
q = cpot[col];
T.data[q].i = M.data[p].j;
T.data[q].j = M.data[p].i;
T.data[q].e = M.data[p].e;
++ cpot[col];//进行完之后加1,表示往后移动一位
}
}
}
//#endif // SEQLIST_H_INCLUDED
/menu.h菜单函数代码/
#ifndef MENU_H_INCLUDED
#define MENU_H_INCLUDED
void menu(){
std::cout<<"\n";
std::cout<<" ************************矩阵转置************************\n";
std::cout<<" * *\n";
std::cout<<" * a:创建矩阵 b:转置矩阵 *\n";
std::cout<<" * c:打印矩阵 d:快速转置矩阵 *\n";
std::cout<<" * e:退出 *\n";
std::cout<<" * *\n";
std::cout<<" ********************************************************\n";
}
#endif // MENU_H_INCLUDED
/主函数代码/
#include <iostream>
#include "menu.h"
#include "Array.h"
using namespace std;
int main()
{
void opration();
opration();
return 0;
}
void opration(){
for(;;){
TSMatrix s,t,r;
menu();
char a;
cin>>a;
switch(a){
case 'a':
init(s);
Print(s);
break;
case 'b':
exchange(s,t);
cout<<"转置之前的矩阵为:"<<endl;
Print(s);
cout<<"转置之后的矩阵为:"<<endl;
Print(t);
break;
case 'c':
cout<<"打印的矩阵为:"<<endl;
Print(s);
break;
case 'd':
quickly(s,r);
cout<<"快速转置之前的矩阵为:"<<endl;
Print(s);
cout<<"快速转置之后的矩阵为:"<<endl;
Print(r);
break;
case 'e':
cout<<"拜拜!!"<<endl;
return ;
break;
default:
cout<<"你输入的序号不正确!!"<<endl;
break;
}
}
}