1 设计型题目
5.1 鞍点问题:若矩阵A中的某一元素A[i,j]是第i行中的最小值,而又是第j列中的最大值,则称A[i,j]是矩阵A中的一个鞍点。写出一个可以确定鞍点位置的程序。
5.2 稀疏矩阵转置:输入稀疏矩阵中每个元素的行号、列号、值,建立稀疏矩阵的三元组存储结构,并将此矩阵转置,显示转置前后的三元组结构。
5.3 (选作)用头尾链表存储表示法建立广义表,输出广义表,求广义表的表头、广义表的表尾和广义表的深度。
2 设计型题目解答
【5.1题解答】:
算法设计思路:
- 遍历数组中的左右行,找出该行的最小值,然后和该列上的元素进行比较,观察是否为列上的最大值
- 如果有多个鞍点,分别存储在数组里,以此输出
- 如果没有鞍点,输出“没有鞍点”。
源代码:
main.cpp
#include <iostream>
#include "Chapter 5_1.h"
//结构体声明
/*
*函数功能:实现矩阵鞍点求解
*/
int main()
{
prepare();//输入矩阵
work();//判断该矩阵上是否有鞍点
printans();//打印输出鞍点
return 0;
}
Chapter 5_1.h
#pragma once
#include <iostream>
using namespace std;
typedef struct node
{
int x, y;
}anstype;
//函数声明
void prepare();//输入一个矩阵
void work();
void printans();//将获取到的鞍点信息打印输出
int check(int x, int y);
void remember(int x, int y);//存储输入的矩阵的值
Chapter 5_1.cpp
#include "Chapter 5_1.h"
#include <iostream>
using namespace std;
//变量声明
int matrix[1000][1000];
anstype ans[1000];
int lenx = 0, leny = -1;
void prepare()
{
//声明局部变量
char tem; //用于接收用户输入的矩阵数值字符
int Intem = -1; //存放用户输入矩阵的最大的列数
//初始化全局变量
lenx = 0;
ans[0].x = 0;
printf("输入一个矩阵:\n");
while (1)
{
//开启新的一行输入时,将列标重置为0
leny = 0;
while (1)
{
//如果用户输入空格,就空循环,直到用户输入非空格的字符
while (tem = getchar(), tem == ' ') {};
if ((tem == '\n') || (tem == EOF))
{
//用户输入回车或EOF时结束对矩阵一行数据的输入
break;
}
//将用户输入的字符转换为数值存入matrix数组
matrix[lenx][leny] = tem - '0';
//将列标指向下一列
leny = leny + 1;
}
if (leny > Intem)
{
//将最大列号存入Intem变量
Intem = leny;
}
if (tem == EOF)
{
//如果用户输入EOF,则退出循环
break;
}
//将行标加1,开启下一行的数据输入
lenx = lenx + 1;
}
//将最大行号写回leny变量,后续函数需要用到
leny = Intem;
}
int check(int x, int y)
{
int i;
for (i = 0; i < lenx; i = i + 1) {
if (matrix[i][y] < matrix[x][y]) return 0;
}
return 1;
}
void remember(int x, int y)
{
ans[0].x = ans[0].x + 1;
ans[ans[0].x].x = x;
ans[ans[0].x].y = y;
}
void work()
{
int i, j;
int tem;
int ColIndex[100] = { 0 };
for (i = 0; i < lenx; i = i + 1)
{
tem = 0;
for (j = 1; j < leny; j = j + 1)
if (matrix[i][j] > matrix[i][tem])
tem = j;
for (j = 0; j < leny; j = j + 1)
{
if (matrix[i][j] == matrix[i][tem])
{
ColIndex[0] = ColIndex[0] + 1;
ColIndex[ColIndex[0]] = j;
}
}
for (j = 1; j <= ColIndex[0]; j = j + 1)
{
if (check(i, ColIndex[j]) == 1) remember(i, ColIndex[j]);
}
}
}
/*
*函数功能:将获取到的鞍点信息打印输出
*/
void printans()
{
if (ans[0].x == 0)
{
printf("没有鞍点\n");
return;
}
int i;
for (i = 1; i <= ans[0].x; i = i + 1)
{
printf("第%d个鞍点是(%d,%d)\n", i, ans[i].x + 1, ans[i].y + 1);
}
}
运行结果截图:
【5.2题解答】:
算法设计思路:
- 输入三元组的思路:逐个输入、逐个存入。
- 转置的思路:普通转置法做双重遍历,查找满足第i列的所有元素,然后存在三元组中。
- 快速转置法,将每一列的非零元个数存在num[i]中,每一列的开始元素存在cpot[i]中。
源代码:
main.cpp
#include "Chapter 5_2.h"
int main() {
TSMatrix T, S,M;
InitSparseMatrix(T);//初始化三元组
TraverseSparseMatrix(T);//打印输出三元组
Transmat(T,S);//一般转置法转置三元组
printf("一般转置法:\n");
TraverseSparseMatrix(S);//将转置后的三元组打印输出
FastTransmat(T,M);//快速转置法转置三元组
printf("快速转置法:\n");
TraverseSparseMatrix(M);//将转置后的三元组打印输出
}
Chapter 5_2.h
#pragma once
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <iostream>
using namespace std;
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define MAXSIZE 100 //三元组的最大存储结构
typedef int Status;
typedef int Elemtype;
typedef struct {
int i, j;
Elemtype e;
}Triple;//三元组的非零元信息
typedef struct {
Triple data[MAXSIZE + 1];
int mu, nu, tu;//矩阵的行数、列数、非零元个数
}TSMatrix;
Status InitSparseMatrix(TSMatrix& T);//初始化三元组
Status TraverseSparseMatrix(TSMatrix T);//矩阵打印输出
Status Transmat(TSMatrix M, TSMatrix& N);//矩阵的转置
Status FastTransmat(TSMatrix M, TSMatrix& N);//矩阵的快速转置
Chapter 5_2.cpp
#include "Chapter 5_2.h"
Status InitSparseMatrix(TSMatrix& T) {
int m, n, t;
printf("请输入总行数、列数、非零元个数\n");
scanf_s("%d %d %d\n", &m, &n, &t);
T.mu = m; T.nu = n; T.tu = t;
//T.tu = 0;
printf("请依次输入三元组的行数、列数、值\n");
for (int i = 1; i <= t; i++) {
int row, col, elem;
scanf_s("%d %d %d ", &row, &col, &elem);
T.data[i].i = row;
T.data[i].j = col;
T.data[i].e = elem;
//T.tu++;
}
return OK;
}
Status TraverseSparseMatrix(TSMatrix T) {
printf("三元组的信息为:\n");
printf("%d %d %d\n", T.mu, T.nu, T.tu);
for (int i = 1; i <=T.tu; i++) {
printf("%d %d %d\n ", T.data[i].i, T.data[i].j, T.data[i].e);
}
return OK;
}
Status Transmat(TSMatrix M, TSMatrix& N) {
N.mu = M.nu; N.nu = M.mu; N.tu = M.tu;
if (M.tu != 0) {
int q = 1;
for (int col = 1; col <= M.nu; col++) {//按M的列转
for (int p = 1; p <= M.tu; p++) {// 对M三元组表扫描一遍
if (M.data[p].j == col) {
N.data[q].i = M.data[p].j;
N.data[q].j = M.data[p].i;
N.data[q].e = M.data[p].e;
q++;//q为N三元组表中的行号
}
}
}
}
//TraverseSparseMatrix(T)
return OK;
}
Status FastTransmat(TSMatrix M, TSMatrix& N) {
N.mu = M.nu; N.nu = M.mu; N.tu = M.tu;
//int t = M.nu;
int num[100];
int cpot[100];
int col, t, p, q;
if (M.tu != 0) {
for (col = 1; col <= M.nu; col++)
num[col] = 0;//初始化num向量
for (t = 1; t <= M.tu; t++)
num[M.data[t].j]++;//求M中每一列含非零元个数
cpot[1] = 1;
for (col = 2; col <= M.nu; col++)
//求M中每一列的第一个非零元在B.data中的序号(位置)
cpot[col] = cpot[col - 1] + num[col - 1];
for (p = 1; p <= M.tu; p++) {
col = M.data[p].j;
q = cpot[col];
N.data[q].i = M.data[p].j;//p为M中的行号
N.data[q].j = M.data[p].i;//q为转置后在N中的行号
N.data[q].e = M.data[p].e;
cpot[col]++;
}
}
return OK;
}
运行结果截图:
【5.3题解答】:
main.cpp
#include "Chapter 5_3.h"
void visit(AtomType e)
{
printf("%c ", e);
}
void main()
{
char p[80];
GList l, m;
HString t;
InitString(&t);
InitGList(&l);
InitGList(&m);
printf("空广义表l的深度=%d l是否空?%d(1:是 0:否)\n", GListDepth(l), GListEmpty(l));
printf("请输入广义表l(书写形式:空表:(),单原子:a,其它:(a,(b),b)):\n");
gets(p);
StrAssign(&t, p);
CreateGList(&l, t);
printf("广义表l的长度=%d\n", GListLength(l));
printf("广义表l的深度=%d l是否空?%d(1:是 0:否)\n", GListDepth(l), GListEmpty(l));
printf("遍历广义表l:\n");
Traverse_GL(l, visit);
printf("\n复制广义表m=l\n");
CopyGList(&m, l);
printf("广义表m的长度=%d\n", GListLength(m));
printf("广义表m的深度=%d\n", GListDepth(m));
printf("遍历广义表m:\n");
Traverse_GL(m, visit);
DestroyGList(&m);
m = GetHead(l);
printf("\nm是l的表头,遍历广义表m:\n");
Traverse_GL(m, visit);
DestroyGList(&m);
m = GetTail(l);
printf("\nm是l的表尾,遍历广义表m:\n");
Traverse_GL(m, visit);
InsertFirst_GL(&m, l);
printf("\n插入l为m的表头,遍历广义表m:\n");
Traverse_GL(m, visit);
printf("\n删除m的表头,遍历广义表m:\n");
DestroyGList(&l);
DeleteFirst_GL(&m, &l);
Traverse_GL(m, visit);
printf("\n");
DestroyGList(&m);
}
Chapter 5_3.h
#pragma once
typedef int Status;
typedef int Boolean;
#include<malloc.h>
#include<process.h>
#include<stdio.h>
#include<limits.h>
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef char AtomType; /* 定义原子类型为字符型 */
typedef enum { ATOM, LIST }ElemTag;
typedef struct GLNode
{
ElemTag tag; /* 公共部分,用于区分原子结点和表结点 */
union /* 原子结点和表结点的联合部分 */
{
AtomType atom; /* atom是原子结点的值域,AtomType由用户定义 */
struct
{
struct GLNode* hp, * tp;
}ptr; /* ptr是表结点的指针域,prt.hp和ptr.tp分别指向表头和表尾 */
}a;
}*GList, GLNode; /* 广义表类型 */
Chapter 5_3.cpp
#include "Chapter 5_3.h"
Status InitGList(GList* L)
{ /* 创建空的广义表L */
*L = NULL;
return OK;
}
void DestroyGList(GList* L) /* 广义表的头尾链表存储的销毁操作 */
{ /* 销毁广义表L */
GList q1, q2;
if (*L)
{
if ((*L)->tag == ATOM)
{
free(*L); /* 删除原子结点 */
*L = NULL;
}
else /* 删除表结点 */
{
q1 = (*L)->a.ptr.hp;
q2 = (*L)->a.ptr.tp;
free(*L);
*L = NULL;
DestroyGList(&q1);
DestroyGList(&q2);
}
}
}
Status CopyGList(GList* T, GList L)
{ /* 采用头尾链表存储结构,由广义表L复制得到广义表T。算法5.6 */
if (!L) /* 复制空表 */
*T = NULL;
else
{
*T = (GList)malloc(sizeof(GLNode)); /* 建表结点 */
if (!*T)
exit(OVERFLOW);
(*T)->tag = L->tag;
if (L->tag == ATOM)
(*T)->a.atom = L->a.atom; /* 复制单原子 */
else
{
CopyGList(&((*T)->a.ptr.hp), L->a.ptr.hp);
/* 复制广义表L->ptr.hp的一个副本T->ptr.hp */
CopyGList(&((*T)->a.ptr.tp), L->a.ptr.tp);
/* 复制广义表L->ptr.tp的一个副本T->ptr.tp */
}
}
return OK;
}
int GListLength(GList L)
{ /* 返回广义表的长度,即元素个数 */
int len = 0;
if (!L)
return 0;
if (L->tag == ATOM)
return 1;
while (L)
{
L = L->a.ptr.tp;
len++;
}
return len;
}
int GListDepth(GList L)
{ /* 采用头尾链表存储结构,求广义表L的深度。算法5.5 */
int max, dep;
GList pp;
if (!L)
return 1; /* 空表深度为1 */
if (L->tag == ATOM)
return 0; /* 原子深度为0 */
for (max = 0, pp = L; pp; pp = pp->a.ptr.tp)
{
dep = GListDepth(pp->a.ptr.hp); /* 求以pp->a.ptr.hp为头指针的子表深度 */
if (dep > max)
max = dep;
}
return max + 1; /* 非空表的深度是各元素的深度的最大值加1 */
}
Status GListEmpty(GList L)
{ /* 判定广义表是否为空 */
if (!L)
return TRUE;
else
return FALSE;
}
GList GetHead(GList L)
{ /* 取广义表L的头 */
GList h, p;
if (!L)
{
printf("空表无表头!\n");
exit(0);
}
p = L->a.ptr.tp;
L->a.ptr.tp = NULL;
CopyGList(&h, L);
L->a.ptr.tp = p;
return h;
}
GList GetTail(GList L)
{ /* 取广义表L的尾 */
GList t;
if (!L)
{
printf("空表无表尾!\n");
exit(0);
}
CopyGList(&t, L->a.ptr.tp);
return t;
}
Status InsertFirst_GL(GList* L, GList e)
{ /* 初始条件: 广义表存在 */
/* 操作结果: 插入元素e作为广义表L的第一元素(表头,也可能是子表) */
GList p = (GList)malloc(sizeof(GLNode));
if (!p)
exit(OVERFLOW);
p->tag = LIST;
p->a.ptr.hp = e;
p->a.ptr.tp = *L;
*L = p;
return OK;
}
Status DeleteFirst_GL(GList* L, GList* e)
{ /* 初始条件: 广义表L存在 */
/* 操作结果: 删除广义表L的第一元素,并用e返回其值 */
GList p;
*e = (*L)->a.ptr.hp;
p = *L;
*L = (*L)->a.ptr.tp;
free(p);
return OK;
}
void Traverse_GL(GList L, void(*v)(AtomType))
{ /* 利用递归算法遍历广义表L */
if (L) /* L不空 */
if (L->tag == ATOM) /* L为单原子 */
v(L->a.atom);
else /* L为广义表 */
{
Traverse_GL(L->a.ptr.hp, v);
Traverse_GL(L->a.ptr.tp, v);
}
}