💡 <05 数据和广义表>习题代码

This commit is contained in:
康建伟
2019-11-15 13:27:08 +08:00
parent a6ee28538e
commit ac49fde6bd
515 changed files with 65873 additions and 0 deletions
+137
View File
@@ -0,0 +1,137 @@
#include <stdio.h>
#include <stdlib.h> // 提供 system、rand、srand 原型
#include <time.h> // 提供 time 原型
#include "SqList.h" //**▲02 线性表**//
// 递归求最大值
int Algo_5_17_1(SqList L, int len);
// 递归求最小值
int Algo_5_17_2(SqList L, int len);
// 递归求和
int Algo_5_17_3(SqList L, int len);
// 递归求积
double Algo_5_17_4(SqList L, int len);
// 递归求平均数
double Algo_5_17_5(SqList L, int len);
int main(int argc, char* argv[]) {
SqList L;
int i;
InitList(&L);
srand((unsigned) time(NULL)); // 用系统时间做随机数种子
for(i = 1; i <= 10; i++) {
ListInsert(&L, i, rand() % 100);
}
printf("顺序表中的数字序列为:");
for(i = 0; i < L.length; i++) {
printf("%d ", L.elem[i]);
}
printf("\n");
printf("顺序表中的最大值为: %d \n", Algo_5_17_1(L, L.length));
printf("顺序表中的最小值为: %d \n", Algo_5_17_2(L, L.length));
printf("顺序表中的和为: %d \n", Algo_5_17_3(L, L.length));
printf("顺序表中的积为: %.2f \n", Algo_5_17_4(L, L.length));
printf("顺序表中的平均值为: %.2f \n", Algo_5_17_5(L, L.length));
return 0;
}
// 递归求最大值
int Algo_5_17_1(SqList L, int len) {
int value, max;
// 获取当前位置的值
GetElem(L, len, &value);
if(len == 1) {
return value;
}
// 获取先前序列的最大值
max = Algo_5_17_1(L, --len);
return max > value ? max : value;
}
// 递归求最小值
int Algo_5_17_2(SqList L, int len) {
int value, min;
// 获取当前位置的值
GetElem(L, len, &value);
if(len == 1) {
return value;
}
// 获取先前序列的最小值
min = Algo_5_17_2(L, --len);
return min < value ? min : value;
}
// 递归求和
int Algo_5_17_3(SqList L, int len) {
int sum;
// 获取当前位置的值
GetElem(L, len, &sum);
if(len == 1) {
return sum;
}
// 获取先前序列的和
sum += Algo_5_17_3(L, --len);
return sum;
}
// 递归求积
double Algo_5_17_4(SqList L, int len) {
int value;
double mul;
// 获取当前位置的值
GetElem(L, len, &value);
mul = value;
if(len == 1) {
return mul;
}
// 获取先前序列的积
mul *= Algo_5_17_4(L, --len);
return mul;
}
// 递归求平均数
double Algo_5_17_5(SqList L, int len) {
int value;
double avg;
// 获取当前位置的值
GetElem(L, len, &value);
avg = value;
if(len == 1) {
return avg;
}
// 获取先前序列的平均数
avg = (Algo_5_17_5(L, len - 1) * (len - 1) + value) / len;
return avg;
}
+7
View File
@@ -0,0 +1,7 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(05.17 SqList.h SqList.c 05.17.c)
# 链接公共库
target_link_libraries(05.17 Scanf_lib)
+337
View File
@@ -0,0 +1,337 @@
/*=============================
* 线性表的顺序存储结构(顺序表)
*
* 包含算法: 2.3、2.4、2.5、2.6
=============================*/
#include "SqList.h"
/*
* ████████ 算法2.3 ████████
*
* 初始化
*
* 初始化成功则返回OK,否则返回ERROR。
*/
Status InitList(SqList* L) {
// 分配指定容量的内存,如果分配失败,则返回NULL
(*L).elem = (ElemType*) malloc(LIST_INIT_SIZE * sizeof(ElemType));
if((*L).elem == NULL) {
// 存储内存失败
exit(OVERFLOW);
}
(*L).length = 0; // 初始化顺序表长度为0
(*L).listsize = LIST_INIT_SIZE; // 顺序表初始内存分配量
return OK; // 初始化成功
}
/*
* 销毁(结构)
*
* 释放顺序表所占内存。
*/
Status DestroyList(SqList* L) {
// 确保顺序表结构存在
if(L == NULL || (*L).elem == NULL) {
return ERROR;
}
// 释放顺序表内存
free((*L).elem);
// 释放内存后置空指针
(*L).elem = NULL;
// 顺序表长度跟容量都归零
(*L).length = 0;
(*L).listsize = 0;
return OK;
}
/*
* 置空(内容)
*
* 只是清理顺序表中存储的数据,不释放顺序表所占内存。
*/
Status ClearList(SqList* L) {
// 确保顺序表结构存在
if(L == NULL || (*L).elem == NULL) {
return ERROR;
}
(*L).length = 0;
return OK;
}
/*
* 判空
*
* 判断顺序表中是否包含有效数据。
*
* 返回值:
* TRUE : 顺序表为空
* FALSE: 顺序表不为空
*/
Status ListEmpty(SqList L) {
return L.length == 0 ? TRUE : FALSE;
}
/*
* 计数
*
* 返回顺序表包含的有效元素的数量。
*/
int ListLength(SqList L) {
return L.length;
}
/*
* 取值
*
* 获取顺序表中第i个元素,将其存储到e中。
* 如果可以找到,返回OK,否则,返回ERROR。
*
*【备注】
* 教材中i的含义是元素位置,从1开始计数,但这不符合编码的通用约定。
* 通常,i的含义应该指索引,即从0开始计数。
*/
Status GetElem(SqList L, int i, ElemType* e) {
// 因为i的含义是位置,所以其合法范围是:[1, length]
if(i < 1 || i > L.length) {
return ERROR; //i值不合法
}
*e = L.elem[i - 1];
return OK;
}
/*
* ████████ 算法2.6 ████████
*
* 查找
*
* 返回顺序表中首个与e满足Compare关系的元素位序。
* 如果不存在这样的元素,则返回0。
*
*【备注】
* 元素e是Compare函数第二个形参
*/
int LocateElem(SqList L, ElemType e, Status(Compare)(ElemType, ElemType)) {
int i;
ElemType* p;
// 确保顺序表结构存在
if(L.elem == NULL) {
return ERROR;
}
/*
* i的初值为第1个元素的位序
*
* 其实,更自然的写法是将i初始化为第1个元素的索引
* 但由于教材中是按位序计数的,所以这里仍写作位序
*/
i = 1;
// p的初值为第1个元素的存储位置
p = L.elem;
// 遍历顺序表
while(i <= L.length && !Compare(*p++, e)) {
++i;
}
if(i <= L.length) {
return i;
} else {
return 0;
}
}
/*
* 前驱
*
* 获取元素cur_e的前驱,
* 如果存在,将其存储到pre_e中,返回OK,
* 如果不存在,则返回ERROR。
*/
Status PriorElem(SqList L, ElemType cur_e, ElemType* pre_e) {
int i;
// 确保顺序表结构存在,且最少包含两个元素
if(L.elem == NULL || L.length < 2) {
return ERROR;
}
// 这里的i初始化为第1个元素的【索引】
i = 0;
// 从第1个元素开始,查找cur_e的位置
while(i < L.length && L.elem[i] != cur_e) {
++i;
}
// 如果cur_e是首个元素(没有前驱),或者没找到元素cur_e,返回ERROR
if(i==0 || i >= L.length) {
return ERROR;
}
// 存储cur_e的前驱
*pre_e = L.elem[i - 1];
return OK;
}
/*
* 后继
*
* 获取元素cur_e的后继,
* 如果存在,将其存储到next_e中,返回OK,
* 如果不存在,则返回ERROR。
*/
Status NextElem(SqList L, ElemType cur_e, ElemType* next_e) {
int i;
// 确保顺序表结构存在,且最少包含两个元素
if(L.elem == NULL || L.length < 2) {
return ERROR;
}
// 这里的i初始化为第1个元素的【索引】
i = 0;
// 从第1个元素开始,查找cur_e的位置
while(i < L.length-1 && L.elem[i] != cur_e) {
++i;
}
// 如果cur_e是最后1个元素(没有前驱),或者没找到元素cur_e,返回ERROR
if(i >= L.length-1) {
return ERROR;
}
// 存储cur_e的前驱
*next_e = L.elem[i + 1];
return OK;
}
/*
* ████████ 算法2.4 ████████
*
* 插入
*
* 向顺序表第i个位置上插入e,插入成功则返回OK,否则返回ERROR。
*
*【备注】
* 教材中i的含义是元素位置,从1开始计数
*/
Status ListInsert(SqList* L, int i, ElemType e) {
ElemType* newbase;
ElemType* p, * q;
// 确保顺序表结构存在
if(L == NULL || (*L).elem == NULL) {
return ERROR;
}
// i值越界
if(i < 1 || i > (*L).length + 1) {
return ERROR;
}
// 若存储空间已满,则增加新空间
if((*L).length >= (*L).listsize) {
// 基于现有空间扩容
newbase = (ElemType*) realloc((*L).elem, ((*L).listsize + LISTINCREMENT) * sizeof(ElemType));
if(newbase == NULL) {
// 存储内存失败
exit(OVERFLOW);
}
// 新基址
(*L).elem = newbase;
// 存的存储空间
(*L).listsize += LISTINCREMENT;
}
// q为插入位置
q = &(*L).elem[i - 1];
// 1.右移元素,腾出位置
for(p = &(*L).elem[(*L).length - 1]; p >= q; --p) {
*(p + 1) = *p;
}
// 2.插入e
*q = e;
// 3.表长增1
(*L).length++;
return OK;
}
/*
* ████████ 算法2.5 ████████
*
* 删除
*
* 删除顺序表第i个位置上的元素,并将被删除元素存储到e中。
* 删除成功则返回OK,否则返回ERROR。
*
*【备注】
* 教材中i的含义是元素位置,从1开始计数
*/
Status ListDelete(SqList* L, int i, ElemType* e) {
ElemType* p, * q;
// 确保顺序表结构存在
if(L == NULL || (*L).elem == NULL) {
return ERROR;
}
// i值越界
if(i < 1 || i > (*L).length) {
return ERROR;
}
// p为被删除元素的位置
p = &(*L).elem[i - 1];
// 1.获取被删除元素
*e = *p;
// 表尾元素位置
q = (*L).elem + (*L).length - 1;
// 2.左移元素,被删除元素的位置上会有新元素进来
for(++p; p <= q; ++p) {
*(p - 1) = *p;
}
// 3.表长减1
(*L).length--;
return OK;
}
/*
* 遍历
*
* 用visit函数访问顺序表L
*/
void ListTraverse(SqList L, void(Visit)(ElemType)) {
int i;
for(i = 0; i < L.length; i++) {
Visit(L.elem[i]);
}
printf("\n");
}
+149
View File
@@ -0,0 +1,149 @@
/*=============================
* 线性表的顺序存储结构(顺序表)
*
* 包含算法: 2.3、2.4、2.5、2.6
=============================*/
#ifndef SQLIST_H
#define SQLIST_H
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
/* 宏定义 */
#define LIST_INIT_SIZE 100 // 顺序表存储空间的初始分配量
#define LISTINCREMENT 10 // 顺序表存储空间的分配增量
/* 顺序表元素类型定义 */
typedef int ElemType;
/*
* 顺序表结构
*
* 注:elem在使用前需要先为其分配内存,且元素从elem[0]处开始存储
*/
typedef struct {
ElemType* elem; // 顺序表存储空间的基址(指向顺序表所占内存的起始位置)
int length; // 当前顺序表长度(包含多少元素)
int listsize; // 当前分配的存储容量(可以存储多少元素)
} SqList;
/*
* ████████ 算法2.3 ████████
*
* 初始化
*
* 初始化成功则返回OK,否则返回ERROR。
*/
Status InitList(SqList* L);
/*
* 销毁(结构)
*
* 释放顺序表所占内存。
*/
Status DestroyList(SqList* L);
/*
* 置空(内容)
*
* 只是清理顺序表中存储的数据,不释放顺序表所占内存。
*/
Status ClearList(SqList* L);
/*
* 判空
*
* 判断顺序表中是否包含有效数据。
*
* 返回值:
* TRUE : 顺序表为空
* FALSE: 顺序表不为空
*/
Status ListEmpty(SqList L);
/*
* 计数
*
* 返回顺序表包含的有效元素的数量。
*/
int ListLength(SqList L);
/*
* 取值
*
* 获取顺序表中第i个元素,将其存储到e中。
* 如果可以找到,返回OK,否则,返回ERROR。
*
*【备注】
* 教材中i的含义是元素位置,从1开始计数,但这不符合编码的通用约定。
* 通常,i的含义应该指索引,即从0开始计数。
*/
Status GetElem(SqList L, int i, ElemType* e);
/*
* ████████ 算法2.6 ████████
*
* 查找
*
* 返回顺序表中首个与e满足Compare关系的元素位序。
* 如果不存在这样的元素,则返回0。
*
*【备注】
* 元素e是Compare函数第二个形参
*/
int LocateElem(SqList L, ElemType e, Status(Compare)(ElemType, ElemType));
/*
* 前驱
*
* 获取元素cur_e的前驱,
* 如果存在,将其存储到pre_e中,返回OK,
* 如果不存在,则返回ERROR。
*/
Status PriorElem(SqList L, ElemType cur_e, ElemType* pre_e);
/*
* 后继
*
* 获取元素cur_e的后继,
* 如果存在,将其存储到next_e中,返回OK,
* 如果不存在,则返回ERROR。
*/
Status NextElem(SqList L, ElemType cur_e, ElemType* next_e);
/*
* ████████ 算法2.4 ████████
*
* 插入
*
* 向顺序表第i个位置上插入e,插入成功则返回OK,否则返回ERROR。
*
*【备注】
* 教材中i的含义是元素位置,从1开始计数
*/
Status ListInsert(SqList* L, int i, ElemType e);
/*
* ████████ 算法2.5 ████████
*
* 删除
*
* 删除顺序表第i个位置上的元素,并将被删除元素存储到e中。
* 删除成功则返回OK,否则返回ERROR。
*
*【备注】
* 教材中i的含义是元素位置,从1开始计数
*/
Status ListDelete(SqList* L, int i, ElemType* e);
/*
* 遍历
*
* 用visit函数访问顺序表L
*/
void ListTraverse(SqList L, void (Visit)(ElemType));
#endif
+91
View File
@@ -0,0 +1,91 @@
#include <stdio.h>
#include <stdlib.h> // 提供 system、rand、srand 原型
#include <time.h> // 提供 time 原型
#include "Status.h" //**▲01 绪论**//
#include "Array.h" //**▲05 数组和广义表**//
/*
* 将数组A中的元素循环右移k个位置
*/
Status Algo_5_18(Array A, int k);
// 逆置[begin, end]范围内的元素
static Status Reversal_5_18(Array A, int begin, int end);
int main(int argc, char* argv[]) {
Array A;
ElemType e;
int i;
int k = 7; // 右移位数
// 初始化长度为10的一维数组
InitArray(&A, 1, 10);
srand((unsigned) time(NULL)); // 用系统时间做随机数种子
for(i = 0; i < Length(A); i++) {
e = rand() % 100;
Assign(&A, e, i);
}
printf("数组A包含的元素为:\n");
for(i = 0; i < Length(A); i++) {
Value(A, &e, i);
printf("%2d ", e);
}
printf("\n");
printf("将数组A循环右移 %d 位后:\n", k);
Algo_5_18(A, k);
for(i = 0; i < Length(A); i++) {
Value(A, &e, i);
printf("%2d ", e);
}
printf("\n");
return 0;
}
/*
* 将数组A中的元素循环右移k个位置
*/
Status Algo_5_18(Array A, int k) {
int n, p;
n = Length(A);
p = k % n; // 计算实际需要循环右移的位数
if(p <= 0) {
return ERROR;
}
Reversal_5_18(A, 0, n-1); // 逆置[0, n-1]范围内的元素
Reversal_5_18(A, 0, p-1); // 逆置[0, p-1]范围内的元素
Reversal_5_18(A, p, n-1); // 逆置[p, n-1]范围内的元素
return OK;
}
// 逆置[begin, end]范围内的元素
static Status Reversal_5_18(Array A, int begin, int end) {
int i;
ElemType e1, e2;
if(begin < 0 || end > Length(A)-1 || begin >= end) {
return ERROR;
}
// 用"交换法"逆置
for(i = 0; i < (end - begin + 1) / 2; i++) {
Value(A, &e1, begin + i); // 获取中点前的元素
Value(A, &e2, end - i); // 获取中点后的元素
// 两元素完成交换
Assign(&A, e2, begin + i);
Assign(&A, e1, end - i);
}
return OK;
}
+195
View File
@@ -0,0 +1,195 @@
/*========
* 多维数组
=========*/
#include "Array.h" //**▲05 数组和广义表**//
/*
* 初始化。
*
* 初始化维数为dim的数组,可变参数指示各维度的大小。
*/
Status InitArray(Array* A, int dim, ...) {
int elemtotal; // 统计数组中总元素个数
va_list ap; // ap存放可变参数表信息,指示各维度的大小
int i;
if(A == NULL) {
return ERROR;
}
if(dim < 1 || dim > MAX_ARRAY_DIM) { // 数组维数有限制
return ERROR;
}
(*A).dim = dim; // 初始化数组维度
// 初始化数组维度信息表
(*A).bounds = (int*) malloc(dim * sizeof(int));
if((*A).bounds == NULL) {
exit(OVERFLOW);
}
// 若维度长度合法,则存入bounds,并求出A的元素总数elemtotal
elemtotal = 1;
// 使ap指向第一个可变参数,dim相当于起始标识
va_start(ap, dim);
for(i = 0; i < dim; i++) {
// 记录当前维度的宽度
(*A).bounds[i] = va_arg(ap, int);
if((*A).bounds[i] <= 0) {
return ERROR;
}
elemtotal *= A->bounds[i];
}
// 置空ap
va_end(ap);
// 初始化数组空间,以存放元素
(*A).base = (ElemType*) malloc(elemtotal * sizeof(ElemType));
if((*A).base == NULL) {
exit(OVERFLOW);
}
// 初始化数组映像函数常量信息表
(*A).constants = (int*) malloc(dim * sizeof(int));
if((*A).constants == NULL) {
exit(OVERFLOW);
}
// 遍历最后一个维度,每次总是需要跨越一个元素
(*A).constants[dim - 1] = 1;
for(i = dim - 2; i >= 0; i--) {
(*A).constants[i] = (*A).bounds[i + 1] * (*A).constants[i + 1];
}
/*
* 举例:
* 对于三维数组[2,3,4]来说,bounds的值为<2,3,4>constants的值为<12,4,1>
* 分析bounds,第一维中包含2个元素,第二维中包含3个元素,第三维中包含4个元素
* 分析constants,遍历第一维,每次需要跨过12个元素,遍历第二维,每次需要跨越4个元素,遍历第三维,每次需要跨越1个元素
*/
return OK;
}
/*
* 销毁(结构)。
*
* 销毁数组占用的空间。
*/
Status DestroyArray(Array* A) {
if(A == NULL || (*A).base == NULL || (*A).bounds == NULL || (*A).constants == NULL) {
return ERROR;
}
free((*A).base);
(*A).base = NULL;
free((*A).bounds);
(*A).bounds = NULL;
free((*A).constants);
(*A).constants = NULL;
(*A).dim = 0;
return OK;
}
/*
* 取值。
*
* 获取指定下标处的元素值,可变参数为dim个下标值,指示待获取元素所在下标。
*/
Status Value(Array A, ElemType* e, ...) {
va_list ap;
Status result;
int off;
va_start(ap, e);
// 计算从起点元素到目标元素需要跨越的元素数量
result = Locate(A, ap, &off);
va_end(ap);
if(result == OVERFLOW) {
return result;
}
*e = *(A.base + off);
return OK;
}
/*
* 赋值。
*
* 为指定下标处的元素赋值,可变参数为dim个下标值,指示待赋值元素所在下标。
*/
Status Assign(Array* A, ElemType e, ...) {
va_list ap;
Status result;
int off;
va_start(ap, e);
// 计算从起点元素到目标元素需要跨越的元素数量
result = Locate(*A, ap, &off);
va_end(ap);
if(result == OVERFLOW) {
return result;
}
*(A->base + off) = e;
return OK;
}
/*
* 求出ap指示的值在数组A中的相对位置,
* 即计算从起点元素到目标元素需要跨越的元素数量。
*/
static Status Locate(Array A, va_list ap, int* off) {
int i, ind;
*off = 0;
for(i = 0; i < A.dim; i++) {
ind = va_arg(ap, int);
// 保证下标不越界
if(ind < 0 || ind >= A.bounds[i]) {
return OVERFLOW;
}
// 某个维度的单位元素个数*需要跨过的单位
*off += A.constants[i] * ind;
}
return OK;
}
/*
* 计算数组中元素的个数
*
*【注】
* 此为新增的函数
*/
int Length(Array A) {
int i;
int elemtotal = 1;
for(i = 0; i < A.dim; i++) {
elemtotal *= A.bounds[i];
}
return elemtotal;
}
+70
View File
@@ -0,0 +1,70 @@
/*========
* 多维数组
=========*/
#ifndef ARRAY_H
#define ARRAY_H
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include <stdarg.h> // 提供宏va_start、va_arg、va_end
#include "Status.h" //**▲01 绪论**//
/* 宏定义 */
#define MAX_ARRAY_DIM 8 // 这里假设数组的最大维度为8
/* 数组元素类型 */
typedef int ElemType;
/* 数组的顺序存储表示 */
typedef struct {
ElemType* base; // 数组元素基址(存放数组元素)
int dim; // 数组维数
int* bounds; // 数组维界基址(存放数组行、列信息)
int* constants; // 数组映像函数常量基址(存储遍历某个维度时,每次需要越过的元素个数)
} Array;
/*
* 初始化。
*
* 初始化维数为dim的数组,可变参数指示各维度的大小。
*/
Status InitArray(Array* A, int dim, ...);
/*
* 销毁(结构)。
*
* 销毁数组占用的空间。
*/
Status DestroyArray(Array* A);
/*
* 取值。
*
* 获取指定下标处的元素值,可变参数为dim个下标值,指示待获取元素所在下标。
*/
Status Value(Array A, ElemType* e, ...);
/*
* 赋值。
*
* 为指定下标处的元素赋值,可变参数为dim个下标值,指示待赋值元素所在下标。
*/
Status Assign(Array* A, ElemType e, ...);
/*
* 求出ap指示的值在数组A中的相对位置,
* 即计算从起点元素到目标元素需要跨越的元素数量。
*/
static Status Locate(Array A, va_list ap, int *off);
/*
* 计算数组中元素的个数
*
*【注】
* 此为新增的函数
*/
int Length(Array A);
#endif
+7
View File
@@ -0,0 +1,7 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(05.18 Array.h Array.c 05.18.c)
# 链接公共库
target_link_libraries(05.18 Scanf_lib)
+114
View File
@@ -0,0 +1,114 @@
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "Array.h" //**▲05 数组和广义表**//
/* 数组元素坐标 */
typedef struct {
int x;
int y;
ElemType value;
} Elem;
/*
* 寻找二维数组A中的马鞍点
*
*【注】
* 数组每行每列的元素不唯一
*/
void Algo_5_19(Array A);
int main(int argc, char* argv[]) {
int a[3][4] = {
{10, 16, 13, 14},
{15, 18, 15, 20},
{ 5, 8, 12, 32}
};
int i, j;
Array A;
// 准备测试数据
InitArray(&A, 2, 3, 4);
for(i = 0; i < 3; i++) {
for(j = 0; j < 4; j++) {
Assign(&A, a[i][j], i, j);
}
}
// 寻找马鞍点
Algo_5_19(A);
return 0;
}
/*
* 寻找二维数组A中的马鞍点
*
*【注】
* 数组每行每列的元素不唯一
*/
void Algo_5_19(Array A) {
int row, col; // 行数与列数
Elem* Min; // 存储数组A中每行的最小值信息
ElemType* Max; // 存储数组A中每列的最大值(只存储值)
int total, k; // total记录Min中存储的元素数量
int i, j;
ElemType e;
int count;
int min;
row = A.bounds[0];
col = A.bounds[1];
Min = (Elem*) malloc(row * col * sizeof(Elem));
Max = (ElemType*) malloc(col * sizeof(ElemType));
// 初始化最大值数组
for(j = 0; j < col; j++) {
Max[j] = INT_MIN;
}
total = 0;
for(i = 0; i < row; i++) {
min = INT_MAX; // 当前行最小值
for(j = 0; j < col; j++) {
// 获取元素A[i][j]
Value(A, &e, i, j);
// 记录最大值
if(e > Max[j]) {
Max[j] = e;
}
// 记录最小值信息
if(e <= min) {
// 每次发现更小的,k都需要重置
if(e < min) {
k = total; // 重新统计当前行的最小值元素数量
min = e;
}
Min[k].x = i;
Min[k].y = j;
Min[k].value = e;
k++;
}
}
// 累加本次新增的元素数量
total += (k - total);
}
count = 0;
for(k = 0; k < total; k++) {
// 如果当前最小值所在列的最大值与当前最小值一致,则遇到了马鞍点
if(Max[Min[k].y] == Min[k].value) {
printf("第 %2d 个马鞍点是位于 (%2d, %2d) 处的 %d\n", ++count, Min[k].x, Min[k].y, Min[k].value);
}
}
}
+178
View File
@@ -0,0 +1,178 @@
/*========
* 多维数组
=========*/
#include "Array.h" //**▲05 数组和广义表**//
/*
* 初始化。
*
* 初始化维数为dim的数组,可变参数指示各维度的大小。
*/
Status InitArray(Array* A, int dim, ...) {
int elemtotal; // 统计数组中总元素个数
va_list ap; // ap存放可变参数表信息,指示各维度的大小
int i;
if(A == NULL) {
return ERROR;
}
if(dim < 1 || dim > MAX_ARRAY_DIM) { // 数组维数有限制
return ERROR;
}
(*A).dim = dim; // 初始化数组维度
// 初始化数组维度信息表
(*A).bounds = (int*) malloc(dim * sizeof(int));
if((*A).bounds == NULL) {
exit(OVERFLOW);
}
// 若维度长度合法,则存入bounds,并求出A的元素总数elemtotal
elemtotal = 1;
// 使ap指向第一个可变参数,dim相当于起始标识
va_start(ap, dim);
for(i = 0; i < dim; i++) {
// 记录当前维度的宽度
(*A).bounds[i] = va_arg(ap, int);
if((*A).bounds[i] <= 0) {
return ERROR;
}
elemtotal *= A->bounds[i];
}
// 置空ap
va_end(ap);
// 初始化数组空间,以存放元素
(*A).base = (ElemType*) malloc(elemtotal * sizeof(ElemType));
if((*A).base == NULL) {
exit(OVERFLOW);
}
// 初始化数组映像函数常量信息表
(*A).constants = (int*) malloc(dim * sizeof(int));
if((*A).constants == NULL) {
exit(OVERFLOW);
}
// 遍历最后一个维度,每次总是需要跨越一个元素
(*A).constants[dim - 1] = 1;
for(i = dim - 2; i >= 0; i--) {
(*A).constants[i] = (*A).bounds[i + 1] * (*A).constants[i + 1];
}
/*
* 举例:
* 对于三维数组[2,3,4]来说,bounds的值为<2,3,4>constants的值为<12,4,1>
* 分析bounds,第一维中包含2个元素,第二维中包含3个元素,第三维中包含4个元素
* 分析constants,遍历第一维,每次需要跨过12个元素,遍历第二维,每次需要跨越4个元素,遍历第三维,每次需要跨越1个元素
*/
return OK;
}
/*
* 销毁(结构)。
*
* 销毁数组占用的空间。
*/
Status DestroyArray(Array* A) {
if(A == NULL || (*A).base == NULL || (*A).bounds == NULL || (*A).constants == NULL) {
return ERROR;
}
free((*A).base);
(*A).base = NULL;
free((*A).bounds);
(*A).bounds = NULL;
free((*A).constants);
(*A).constants = NULL;
(*A).dim = 0;
return OK;
}
/*
* 取值。
*
* 获取指定下标处的元素值,可变参数为dim个下标值,指示待获取元素所在下标。
*/
Status Value(Array A, ElemType* e, ...) {
va_list ap;
Status result;
int off;
va_start(ap, e);
// 计算从起点元素到目标元素需要跨越的元素数量
result = Locate(A, ap, &off);
va_end(ap);
if(result == OVERFLOW) {
return result;
}
*e = *(A.base + off);
return OK;
}
/*
* 赋值。
*
* 为指定下标处的元素赋值,可变参数为dim个下标值,指示待赋值元素所在下标。
*/
Status Assign(Array* A, ElemType e, ...) {
va_list ap;
Status result;
int off;
va_start(ap, e);
// 计算从起点元素到目标元素需要跨越的元素数量
result = Locate(*A, ap, &off);
va_end(ap);
if(result == OVERFLOW) {
return result;
}
*(A->base + off) = e;
return OK;
}
/*
* 求出ap指示的值在数组A中的相对位置,
* 即计算从起点元素到目标元素需要跨越的元素数量。
*/
static Status Locate(Array A, va_list ap, int* off) {
int i, ind;
*off = 0;
for(i = 0; i < A.dim; i++) {
ind = va_arg(ap, int);
// 保证下标不越界
if(ind < 0 || ind >= A.bounds[i]) {
return OVERFLOW;
}
// 某个维度的单位元素个数*需要跨过的单位
*off += A.constants[i] * ind;
}
return OK;
}
+62
View File
@@ -0,0 +1,62 @@
/*========
* 多维数组
=========*/
#ifndef ARRAY_H
#define ARRAY_H
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include <stdarg.h> // 提供宏va_start、va_arg、va_end
#include "Status.h" //**▲01 绪论**//
/* 宏定义 */
#define MAX_ARRAY_DIM 8 // 这里假设数组的最大维度为8
/* 数组元素类型 */
typedef int ElemType;
/* 数组的顺序存储表示 */
typedef struct {
ElemType* base; // 数组元素基址(存放数组元素)
int dim; // 数组维数
int* bounds; // 数组维界基址(存放数组行、列信息)
int* constants; // 数组映像函数常量基址(存储遍历某个维度时,每次需要越过的元素个数)
} Array;
/*
* 初始化。
*
* 初始化维数为dim的数组,可变参数指示各维度的大小。
*/
Status InitArray(Array* A, int dim, ...);
/*
* 销毁(结构)。
*
* 销毁数组占用的空间。
*/
Status DestroyArray(Array* A);
/*
* 取值。
*
* 获取指定下标处的元素值,可变参数为dim个下标值,指示待获取元素所在下标。
*/
Status Value(Array A, ElemType* e, ...);
/*
* 赋值。
*
* 为指定下标处的元素赋值,可变参数为dim个下标值,指示待赋值元素所在下标。
*/
Status Assign(Array* A, ElemType e, ...);
/*
* 求出ap指示的值在数组A中的相对位置,
* 即计算从起点元素到目标元素需要跨越的元素数量。
*/
static Status Locate(Array A, va_list ap, int *off);
#endif
+7
View File
@@ -0,0 +1,7 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(05.19 Array.h Array.c 05.19.c)
# 链接公共库
target_link_libraries(05.19 Scanf_lib)
+112
View File
@@ -0,0 +1,112 @@
#include <stdio.h>
#include <stdlib.h> // 提供 system、rand、srand 原型
#include <time.h> // 提供 time 原型
#include "Array.h" //**▲05 数组和广义表**//
// 根据多项式系数表,输出多项式
void Algo_5_20(Array A);
// 数组输出函数的内部实现
static void Print(Array A, int dim, int index[]);
int main(int argc, char* argv[]) {
Array A;
int i, j, k;
ElemType e = 0;
// 初始化一个维度为<2,3,4>的三维数组
InitArray(&A, 3, 2, 3, 4);
srand((unsigned) time(NULL)); // 用系统时间做随机数种子
// 准备测试数据
for(i = 0; i < A.bounds[0]; i++) {
for(j = 0; j < A.bounds[1]; j++) {
for(k = 0; k < A.bounds[2]; k++) {
e = rand() % 50 - 25; // 用随机数填充数组
Assign(&A, e, i, j, k);
}
}
}
// 输出多项式
Algo_5_20(A);
return 0;
}
// 根据多项式系数表,输出多项式
void Algo_5_20(Array A) {
int i;
int* index;
// 在遍历数组元素时,记录每个元素的索引(只记录前dim-1维)
index = (int*) malloc((A.dim - 1) * sizeof(int));
for(i = 0; i < A.dim - 1; i++) {
index[i] = -1;
}
Print(A, 1, index);
printf("\n");
}
// 数组输出函数的内部实现
static void Print(Array A, int dim, int index[]) {
int i, j;
int start;
ElemType coef;
if(dim == A.dim) {
start = 0;
// 计算本次遍历的起始元素位置
for(i = 0; i < dim - 1; i++) {
start += index[i] * A.constants[i];
}
// 遍历最后一个维度内的元素
for(i = 0; i < A.bounds[dim - 1]; i++) {
// 获取系数
coef = A.base[start + i];
// 系数为0的项不必输出
if(coef == 0) {
continue;
}
if(coef < 0) {
printf(" - ");
} else {
printf(" + ");
}
// 系数的绝对值为1时,无需输出系数
if(abs(coef) != 1) {
// 输出系数(不带符号,前面已经输出过符号),第一项也会带着符号
printf("%d", abs(coef));
}
/*
* 输出多项式的每一项,未知数依次用a、b、c...命名
*
*【注】
* 对于指数位0或者指数位1的情形,这里依然将其打印出来了
* 可以选择不打印这些标记
*/
for(j = 0; j < dim - 1; j++) {
printf("%c^%d", 'a' + j, index[j]);
}
printf("%c^%d", 'a' + j, i);
}
} else {
for(i = 0; i < A.bounds[dim - 1]; i++) {
// 索引轮转
index[dim - 1] = (index[dim - 1] + 1 + A.bounds[dim - 1]) % A.bounds[dim - 1];
Print(A, dim + 1, index);
}
}
}
+178
View File
@@ -0,0 +1,178 @@
/*========
* 多维数组
=========*/
#include "Array.h" //**▲05 数组和广义表**//
/*
* 初始化。
*
* 初始化维数为dim的数组,可变参数指示各维度的大小。
*/
Status InitArray(Array* A, int dim, ...) {
int elemtotal; // 统计数组中总元素个数
va_list ap; // ap存放可变参数表信息,指示各维度的大小
int i;
if(A == NULL) {
return ERROR;
}
if(dim < 1 || dim > MAX_ARRAY_DIM) { // 数组维数有限制
return ERROR;
}
(*A).dim = dim; // 初始化数组维度
// 初始化数组维度信息表
(*A).bounds = (int*) malloc(dim * sizeof(int));
if((*A).bounds == NULL) {
exit(OVERFLOW);
}
// 若维度长度合法,则存入bounds,并求出A的元素总数elemtotal
elemtotal = 1;
// 使ap指向第一个可变参数,dim相当于起始标识
va_start(ap, dim);
for(i = 0; i < dim; i++) {
// 记录当前维度的宽度
(*A).bounds[i] = va_arg(ap, int);
if((*A).bounds[i] <= 0) {
return ERROR;
}
elemtotal *= A->bounds[i];
}
// 置空ap
va_end(ap);
// 初始化数组空间,以存放元素
(*A).base = (ElemType*) malloc(elemtotal * sizeof(ElemType));
if((*A).base == NULL) {
exit(OVERFLOW);
}
// 初始化数组映像函数常量信息表
(*A).constants = (int*) malloc(dim * sizeof(int));
if((*A).constants == NULL) {
exit(OVERFLOW);
}
// 遍历最后一个维度,每次总是需要跨越一个元素
(*A).constants[dim - 1] = 1;
for(i = dim - 2; i >= 0; i--) {
(*A).constants[i] = (*A).bounds[i + 1] * (*A).constants[i + 1];
}
/*
* 举例:
* 对于三维数组[2,3,4]来说,bounds的值为<2,3,4>constants的值为<12,4,1>
* 分析bounds,第一维中包含2个元素,第二维中包含3个元素,第三维中包含4个元素
* 分析constants,遍历第一维,每次需要跨过12个元素,遍历第二维,每次需要跨越4个元素,遍历第三维,每次需要跨越1个元素
*/
return OK;
}
/*
* 销毁(结构)。
*
* 销毁数组占用的空间。
*/
Status DestroyArray(Array* A) {
if(A == NULL || (*A).base == NULL || (*A).bounds == NULL || (*A).constants == NULL) {
return ERROR;
}
free((*A).base);
(*A).base = NULL;
free((*A).bounds);
(*A).bounds = NULL;
free((*A).constants);
(*A).constants = NULL;
(*A).dim = 0;
return OK;
}
/*
* 取值。
*
* 获取指定下标处的元素值,可变参数为dim个下标值,指示待获取元素所在下标。
*/
Status Value(Array A, ElemType* e, ...) {
va_list ap;
Status result;
int off;
va_start(ap, e);
// 计算从起点元素到目标元素需要跨越的元素数量
result = Locate(A, ap, &off);
va_end(ap);
if(result == OVERFLOW) {
return result;
}
*e = *(A.base + off);
return OK;
}
/*
* 赋值。
*
* 为指定下标处的元素赋值,可变参数为dim个下标值,指示待赋值元素所在下标。
*/
Status Assign(Array* A, ElemType e, ...) {
va_list ap;
Status result;
int off;
va_start(ap, e);
// 计算从起点元素到目标元素需要跨越的元素数量
result = Locate(*A, ap, &off);
va_end(ap);
if(result == OVERFLOW) {
return result;
}
*(A->base + off) = e;
return OK;
}
/*
* 求出ap指示的值在数组A中的相对位置,
* 即计算从起点元素到目标元素需要跨越的元素数量。
*/
static Status Locate(Array A, va_list ap, int* off) {
int i, ind;
*off = 0;
for(i = 0; i < A.dim; i++) {
ind = va_arg(ap, int);
// 保证下标不越界
if(ind < 0 || ind >= A.bounds[i]) {
return OVERFLOW;
}
// 某个维度的单位元素个数*需要跨过的单位
*off += A.constants[i] * ind;
}
return OK;
}
+62
View File
@@ -0,0 +1,62 @@
/*========
* 多维数组
=========*/
#ifndef ARRAY_H
#define ARRAY_H
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include <stdarg.h> // 提供宏va_start、va_arg、va_end
#include "Status.h" //**▲01 绪论**//
/* 宏定义 */
#define MAX_ARRAY_DIM 8 // 这里假设数组的最大维度为8
/* 数组元素类型 */
typedef int ElemType;
/* 数组的顺序存储表示 */
typedef struct {
ElemType* base; // 数组元素基址(存放数组元素)
int dim; // 数组维数
int* bounds; // 数组维界基址(存放数组行、列信息)
int* constants; // 数组映像函数常量基址(存储遍历某个维度时,每次需要越过的元素个数)
} Array;
/*
* 初始化。
*
* 初始化维数为dim的数组,可变参数指示各维度的大小。
*/
Status InitArray(Array* A, int dim, ...);
/*
* 销毁(结构)。
*
* 销毁数组占用的空间。
*/
Status DestroyArray(Array* A);
/*
* 取值。
*
* 获取指定下标处的元素值,可变参数为dim个下标值,指示待获取元素所在下标。
*/
Status Value(Array A, ElemType* e, ...);
/*
* 赋值。
*
* 为指定下标处的元素赋值,可变参数为dim个下标值,指示待赋值元素所在下标。
*/
Status Assign(Array* A, ElemType e, ...);
/*
* 求出ap指示的值在数组A中的相对位置,
* 即计算从起点元素到目标元素需要跨越的元素数量。
*/
static Status Locate(Array A, va_list ap, int *off);
#endif
+7
View File
@@ -0,0 +1,7 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(05.20 Array.h Array.c 05.20.c)
# 链接公共库
target_link_libraries(05.20 Scanf_lib)
+43
View File
@@ -0,0 +1,43 @@
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
#include "TSMatrix.h" //**▲05 数组和广义表**//
/*
* 稀疏矩阵加法:AddSMatrix
*
*【注】
* 该函数已在TSMatrix相关文件中定义
*/
Status Algo_5_21(TSMatrix A, TSMatrix B, TSMatrix* C);
int main(int argc, char* argv[]) {
TSMatrix A, B, C;
printf("█ 创建两个稀疏矩阵 A、B ...\n");
CreateSMatrix(&A, "TestData_A.txt");
CreateSMatrix(&B, "TestData_B.txt");
printf("█ A = \n");
PrintSMatrix(A);
printf("█ B = \n");
PrintSMatrix(B);
// 矩阵相加
Algo_5_21(A, B, &C);
printf("█ C = A + B = \n");
PrintSMatrix(C);
return 0;
}
/*
* 稀疏矩阵加法:AddSMatrix
*
*【注】
* 该函数已在TSMatrix相关文件中定义
*/
Status Algo_5_21(TSMatrix A, TSMatrix B, TSMatrix* C) {
return AddSMatrix(A, B, C);
}
+13
View File
@@ -0,0 +1,13 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(05.21 TSMatrix.h TSMatrix.c 05.21.c)
# 链接公共库
target_link_libraries(05.21 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+433
View File
@@ -0,0 +1,433 @@
/*=======================
* 三元组顺序表(稀疏矩阵)
*
* 包含算法: 5.1、5.2
========================*/
#include "TSMatrix.h" //**▲05 数组和广义表**//
/*
* 创建稀疏矩阵M
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateSMatrix(TSMatrix* M, char* path) {
int k;
FILE* fp;
int readFromConsole; // 是否从控制台读取数据
// 如果没有文件路径信息,则从控制台读取输入
readFromConsole = path == NULL || strcmp(path, "") == 0;
// 如果没有文件路径信息,则从控制台读取输入
if(readFromConsole) {
printf("请输入行数:");
scanf("%d", &((*M).mu));
printf("请输入列数:");
scanf("%d", &((*M).nu));
printf("请输入非零元素个数:");
scanf("%d", &((*M).tu));
printf("请输入%d个三元组信息\n", (*M).tu);
for(k = 1; k <= (*M).tu; k++) {
printf("第%2d组:", k);
scanf("%d%d%d", &((*M).data[k].i), &((*M).data[k].j), &((*M).data[k].e));
}
} else {
fp = fopen(path, "r");
ReadData(fp, "%d%d%d", &((*M).mu), &((*M).nu), &((*M).tu));
for(k = 1; k <= (*M).tu; k++) {
ReadData(fp, "%d%d%d", &((*M).data[k].i), &((*M).data[k].j), &((*M).data[k].e));
}
fclose(fp);
}
return OK;
}
/*
* 销毁稀疏矩阵
*
*【注】
* 三元组顺序表的结构无法销毁。
*/
Status DestroySMatrix(TSMatrix* M) {
if(M == NULL) {
return ERROR;
}
(*M).mu = 0;
(*M).nu = 0;
(*M).tu = 0;
return OK;
}
/*
* 矩阵复制
*
* 创建一个新矩阵T,该矩阵包含了从矩阵M中包含的数据。
*/
Status CopySMatrix(TSMatrix M, TSMatrix* T) {
(*T) = M; // 结构体之间可以直接复制,即使内部包含数组也可以
return OK;
}
/*
* 矩阵加法
*
* Q = M + N。
*/
Status AddSMatrix(TSMatrix M, TSMatrix N, TSMatrix* Q) {
int m, n, k;
if(M.mu != N.mu || M.nu != N.nu) {
printf("两矩阵的行数、列数不满足相加条件!!\n");
return ERROR;
}
// 初始化Q
(*Q).mu = M.mu;
(*Q).nu = M.nu;
(*Q).tu = 0;
m = n = k = 1;
// 依次遍历M与N的三元组
while(m <= M.tu && n <= N.tu) {
// M中的三元组行下标较小
if(M.data[m].i < N.data[n].i) {
(*Q).data[k] = M.data[m];
m++;
// N中的三元组行下标较小
} else if(M.data[m].i > N.data[n].i) {
(*Q).data[k] = N.data[n];
n++;
// M与N中的三元组行下标一致,需要进一步比较列坐标
} else {
// M中的三元组列下标较小
if(M.data[m].j < N.data[n].j) {
(*Q).data[k] = M.data[m];
m++;
// N中的三元组列下标较小
} else if(M.data[m].j > N.data[n].j) {
(*Q).data[k] = N.data[n];
n++;
// M与N中的三元组列下标一致,需要进行加法运算
} else {
// 值已经加为0的话,不需要存储该元素
if((M.data[m].e + N.data[n].e) == 0) {
m++;
n++;
continue;
} else {
(*Q).data[k].i = M.data[m].i;
(*Q).data[k].j = M.data[m].j;
(*Q).data[k].e = M.data[m].e + N.data[n].e;
m++;
n++;
}
}
}
k++;
(*Q).tu++;
}
// 遍历M中剩余的三元组
while(m <= M.tu) {
(*Q).data[k] = M.data[m];
m++;
k++;
(*Q).tu++;
}
// 遍历N中剩余的三元组
while(n <= N.tu) {
(*Q).data[k] = N.data[n];
n++;
k++;
(*Q).tu++;
}
return OK;
}
/*
* 矩阵减法
*
* Q = M - N。
*/
Status SubSMatrix(TSMatrix M, TSMatrix N, TSMatrix* Q) {
int m, n, k;
if(M.mu != N.mu || M.nu != N.nu) {
printf("两矩阵的行数、列数不满足相减条件!!\n");
return ERROR;
}
// 初始化Q
(*Q).mu = M.mu;
(*Q).nu = M.nu;
(*Q).tu = 0;
m = n = k = 1;
// 依次遍历M与N的三元组
while(m <= M.tu && n <= N.tu) {
// M中的三元组行下标较小
if(M.data[m].i < N.data[n].i) {
(*Q).data[k] = M.data[m];
m++;
// N中的三元组行下标较小
} else if(M.data[m].i > N.data[n].i) {
(*Q).data[k].i = N.data[n].i;
(*Q).data[k].j = N.data[n].j;
(*Q).data[k].e = -N.data[n].e; // 由于是相减,所以要对元素值取相反数
n++;
// M与N中的三元组行下标一致,需要进一步比较列坐标
} else {
// M中的三元组列下标较小
if(M.data[m].j < N.data[n].j) {
(*Q).data[k] = M.data[m];
m++;
// N中的三元组列下标较小
} else if(M.data[m].j > N.data[n].j) {
(*Q).data[k].i = N.data[n].i;
(*Q).data[k].j = N.data[n].j;
(*Q).data[k].e = -N.data[n].e; // 由于是相减,所以要对元素值取相反数
n++;
// M与N中的三元组列下标一致,需要进行减法运算
} else {
// 值已经减为0的话,不需要存储该元素
if((M.data[m].e - N.data[n].e) == 0) {
m++;
n++;
continue;
} else {
(*Q).data[k].i = M.data[m].i;
(*Q).data[k].j = M.data[m].j;
(*Q).data[k].e = M.data[m].e - N.data[n].e;
m++;
n++;
}
}
}
k++;
(*Q).tu++;
}
// 遍历M中剩余的三元组
while(m <= M.tu) {
(*Q).data[k] = M.data[m];
m++;
k++;
(*Q).tu++;
}
// 遍历N中剩余的三元组
while(n <= N.tu) {
(*Q).data[k].i = N.data[n].i;
(*Q).data[k].j = N.data[n].j;
(*Q).data[k].e = -N.data[n].e;
n++;
k++;
(*Q).tu++;
}
return OK;
}
/*
* 矩阵乘法
*
* Q = M * N,这里实现的是传统矩阵乘法。
*/
Status MultSMatrix(TSMatrix M, TSMatrix N, TSMatrix* Q) {
int m, n, i, j, k;
ElemType c, c1, c2;
// M的列数需要等于N的行数
if(M.nu != N.mu) {
printf("两矩阵的行数、列数不满足相乘条件!!\n");
return ERROR;
}
// 初始化Q
(*Q).mu = M.mu;
(*Q).nu = N.nu;
(*Q).tu = 0;
// 如果存在零矩阵
if(M.tu * N.tu == 0) {
return OK;
}
// 遍历矩阵M的行
for(i = 1; i <= M.mu; i++) {
// 遍历矩阵N的列
for(j = 1; j <= N.nu; j++) {
c = 0;
for(k = 1; k <= M.nu; k++) {
// 记录M[i][k]的值
c1 = 0;
// 依次寻找位于指定位置的M三元组
for(m = 1; m <= M.tu; m++) {
if(M.data[m].i == i && M.data[m].j == k) {
c1 = M.data[m].e;
break;
}
}
// 记录N[k][j]的值
c2 = 0;
//依次寻找位于指定位置的N三元组
for(n = 1; n <= N.tu; n++) {
if(N.data[n].i == k && N.data[n].j == j) {
c2 = N.data[n].e;
break;
}
}
// 计算Q[i][j]的值
if(c1 && c2) {
c += c1 * c2;
}
}
// 如果计算结果不为0,则进行存储
if(c != 0) {
(*Q).tu++;
(*Q).data[(*Q).tu].i = i;
(*Q).data[(*Q).tu].j = j;
(*Q).data[(*Q).tu].e = c;
}
}
}
return OK;
}
/*
* ████████ 算法5.1 ████████
*
* 矩阵转置
*/
Status TransposeSMatrix(TSMatrix M, TSMatrix* T) {
int p, q, col;
(*T).mu = M.nu;
(*T).nu = M.mu;
(*T).tu = M.tu;
if((*T).tu != 0) {
q = 1; // q用于T中非零元的计数
// col代表M的列,T的行
for(col = 1; col <= M.nu; ++col) {
// 在M中查找第j列的元素,依次将其转置到T中
for(p = 1; p <= M.tu; ++p) {
if(M.data[p].j == col) {
(*T).data[q].i = M.data[p].j; // M的列变为T的行
(*T).data[q].j = M.data[p].i; // M的行变为T的列
(*T).data[q].e = M.data[p].e; // 每个三元组值不变
++q;
}
}
}
}
return OK;
}
/*
* ████████ 算法5.2 ████████
*
* 矩阵快速转置
*/
Status FastTransposeSMatrix(TSMatrix M, TSMatrix* T) {
int col, t, p, q;
int* num; // num[col] 表示M第col列中非零元的个数
int* copt; // copt[col]表示M第col列第一个非零元在转置后矩阵中的位置
(*T).mu = M.nu;
(*T).nu = M.mu;
(*T).tu = M.tu;
// 提前返回
if((*T).tu == 0) {
return ERROR;
}
num = (int*) malloc(M.nu * sizeof(int));
copt = (int*) malloc(M.nu * sizeof(int));
// 初始化数组num
for(col = 1; col <= M.nu; ++col) {
num[col] = 0;
}
// 统计M中的非零元,统计每列非零元的个数
for(t = 1; t <= M.tu; ++t) {
num[M.data[t].j]++;
}
// 第1列第1个非零元总是位于转置后矩阵中的首位
copt[1] = 1;
// 计算各列第1个非零元在转置矩阵中的位置
for(col = 2; col <= M.nu; ++col) {
copt[col] = copt[col - 1] + num[col - 1];
}
// 依次扫描M中的三元组
for(p = 1; p <= M.tu; ++p) {
col = M.data[p].j; // 计算当前非零元所处的列
q = copt[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;
++copt[col]; // 再遇到此列元素时,其在转置矩阵中的位置应当增一(该步骤很重要)
}
return OK;
}
/*
* 输出矩阵
*/
void PrintSMatrix(TSMatrix M) {
int r, c;
int k = 1;
for(r = 1; r <= M.mu; r++) {
for(c = 1; c <= M.nu; c++) {
if(r == M.data[k].i && c == M.data[k].j) {
printf("%3d ", M.data[k].e);
k++;
} else {
printf("%3d ", 0);
}
}
printf("\n");
}
}
+104
View File
@@ -0,0 +1,104 @@
/*=======================
* 三元组顺序表(稀疏矩阵)
*
* 包含算法: 5.1、5.2
========================*/
#ifndef TSMATRIX_H
#define TSMATRIX_H
#include <stdio.h>
#include <stdlib.h> // 提供 malloc 原型
#include <string.h> // 提供 strstr 原型
#include "Status.h" //**▲01 绪论**//
/* 宏定义 */
#define MAXSIZE 12500 // 非零元数量的最大值
/* 三元组稀疏矩阵元素类型 */
typedef int ElemType;
/* 三元组类型定义,主要用来存储非零元 */
typedef struct {
int i, j; // 该三元组非零元的行下标和列下标
ElemType e;
} Triple;
/* 三元组稀疏矩阵类型定义 */
typedef struct {
Triple data[MAXSIZE + 1]; // 非零元三元组表,data[0]未用
int mu, nu, tu; // 矩阵的行数、列数和非零元个数
} TSMatrix;
/*
* 创建稀疏矩阵M
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateSMatrix(TSMatrix* M, char* path);
/*
* 销毁稀疏矩阵
*
*【注】
* 三元组顺序表的结构无法销毁。
*/
Status DestroySMatrix(TSMatrix* M);
/*
* 矩阵复制
*
* 创建一个新矩阵T,该矩阵包含了从矩阵M中包含的数据。
*/
Status CopySMatrix(TSMatrix M, TSMatrix* T);
/*
* 矩阵加法
*
* Q = M + N。
*/
Status AddSMatrix(TSMatrix M, TSMatrix N, TSMatrix* Q);
/*
* 矩阵减法
*
* Q = M - N。
*/
Status SubSMatrix(TSMatrix M, TSMatrix N, TSMatrix* Q);
/*
* 矩阵乘法
*
* Q = M * N,这里实现的是传统矩阵乘法。
*/
Status MultSMatrix(TSMatrix M, TSMatrix N, TSMatrix* Q);
/*
* ████████ 算法5.1 ████████
*
* 矩阵转置
*/
Status TransposeSMatrix(TSMatrix M, TSMatrix* T);
/*
* ████████ 算法5.2 ████████
*
* 矩阵快速转置
*/
Status FastTransposeSMatrix(TSMatrix M, TSMatrix* T);
/*
* 输出矩阵
*/
void PrintSMatrix(TSMatrix M);
#endif
+4
View File
@@ -0,0 +1,4 @@
行数:5
列数:5
非零元个数:10
三元组:(1,2,1),(1,4,5),(2,3,-3),(2,5,2),(3,1,2),(3,2,3),(3,3,4),(4,4,2),(5,1,3),(5,2,-1)
+4
View File
@@ -0,0 +1,4 @@
行数:5
列数:5
非零元个数:8
三元组:(1,1,-3)(1,3,2)(2,4,-1)(3,2,4)(4,1,6)(4,5,5)(5,1,3)(5,3,2)
+106
View File
@@ -0,0 +1,106 @@
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
#include "TSMatrix.h" //**▲05 数组和广义表**//
/*
* 稀疏矩阵加法:AddSMatrix
*
*【注】
* 计算结果需要保存到原矩阵A中
*/
Status Algo_5_22(TSMatrix* A, TSMatrix B);
int main(int argc, char* argv[]) {
TSMatrix A, B;
printf("█ 创建两个稀疏矩阵 A、B ...\n");
CreateSMatrix(&A, "TestData_A.txt");
CreateSMatrix(&B, "TestData_B.txt");
printf("█ A = \n");
PrintSMatrix(A);
printf("█ B = \n");
PrintSMatrix(B);
// 矩阵相加
Algo_5_22(&A, B);
printf("█ A = A + B = \n");
PrintSMatrix(A);
return 0;
}
/*
* 稀疏矩阵加法:AddSMatrix
*
*【注】
* 计算结果需要保存到原矩阵A中
*/
Status Algo_5_22(TSMatrix* A, TSMatrix B) {
int m, n, k;
if((*A).mu != B.mu || (*A).nu != B.nu) {
printf("两矩阵的行数、列数不满足相加条件!!\n");
return ERROR;
}
// A中元素向后移动,移动长度为B的元素个数
for(k = (*A).tu; k > 0; k--) {
(*A).data[k + B.tu] = (*A).data[k];
}
m = B.tu + 1; // 遍历A的起点
n = 1; // 遍历B的起点
k = 0; // 指向计算结果的游标
// 依次遍历A与B的三元组
while(m <= (*A).tu + B.tu && n <= B.tu) {
// A中的三元组行下标较小
if((*A).data[m].i < B.data[n].i) {
(*A).data[++k] = (*A).data[m++];
// B中的三元组行下标较小
} else if((*A).data[m].i > B.data[n].i) {
(*A).data[++k] = B.data[n++];
// A与B中的三元组行下标一致,需要进一步比较列坐标
} else {
// A中的三元组列下标较小
if((*A).data[m].j < B.data[n].j) {
(*A).data[++k] = (*A).data[m++];
// B中的三元组列下标较小
} else if((*A).data[m].j > B.data[n].j) {
(*A).data[++k] = B.data[n++];
// A与B中的三元组列下标一致,需要进行加法运算
} else {
// 值不为0时,需要存储该元素
if(((*A).data[m].e + B.data[n].e) != 0) {
k++;
(*A).data[k].i = (*A).data[m].i;
(*A).data[k].j = (*A).data[m].j;
(*A).data[k].e = (*A).data[m].e + B.data[n].e;
}
m++;
n++;
}
}
}
// 遍历A中剩余的三元组
while(m <= (*A).tu + B.tu) {
(*A).data[++k] = (*A).data[m++];
}
// 遍历B中剩余的三元组
while(n <= B.tu) {
(*A).data[++k] = B.data[n++];
}
(*A).tu = k;
return OK;
}
+13
View File
@@ -0,0 +1,13 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(05.22 TSMatrix.h TSMatrix.c 05.22.c)
# 链接公共库
target_link_libraries(05.22 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+433
View File
@@ -0,0 +1,433 @@
/*=======================
* 三元组顺序表(稀疏矩阵)
*
* 包含算法: 5.1、5.2
========================*/
#include "TSMatrix.h" //**▲05 数组和广义表**//
/*
* 创建稀疏矩阵M
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateSMatrix(TSMatrix* M, char* path) {
int k;
FILE* fp;
int readFromConsole; // 是否从控制台读取数据
// 如果没有文件路径信息,则从控制台读取输入
readFromConsole = path == NULL || strcmp(path, "") == 0;
// 如果没有文件路径信息,则从控制台读取输入
if(readFromConsole) {
printf("请输入行数:");
scanf("%d", &((*M).mu));
printf("请输入列数:");
scanf("%d", &((*M).nu));
printf("请输入非零元素个数:");
scanf("%d", &((*M).tu));
printf("请输入%d个三元组信息\n", (*M).tu);
for(k = 1; k <= (*M).tu; k++) {
printf("第%2d组:", k);
scanf("%d%d%d", &((*M).data[k].i), &((*M).data[k].j), &((*M).data[k].e));
}
} else {
fp = fopen(path, "r");
ReadData(fp, "%d%d%d", &((*M).mu), &((*M).nu), &((*M).tu));
for(k = 1; k <= (*M).tu; k++) {
ReadData(fp, "%d%d%d", &((*M).data[k].i), &((*M).data[k].j), &((*M).data[k].e));
}
fclose(fp);
}
return OK;
}
/*
* 销毁稀疏矩阵
*
*【注】
* 三元组顺序表的结构无法销毁。
*/
Status DestroySMatrix(TSMatrix* M) {
if(M == NULL) {
return ERROR;
}
(*M).mu = 0;
(*M).nu = 0;
(*M).tu = 0;
return OK;
}
/*
* 矩阵复制
*
* 创建一个新矩阵T,该矩阵包含了从矩阵M中包含的数据。
*/
Status CopySMatrix(TSMatrix M, TSMatrix* T) {
(*T) = M; // 结构体之间可以直接复制,即使内部包含数组也可以
return OK;
}
/*
* 矩阵加法
*
* Q = M + N。
*/
Status AddSMatrix(TSMatrix M, TSMatrix N, TSMatrix* Q) {
int m, n, k;
if(M.mu != N.mu || M.nu != N.nu) {
printf("两矩阵的行数、列数不满足相加条件!!\n");
return ERROR;
}
// 初始化Q
(*Q).mu = M.mu;
(*Q).nu = M.nu;
(*Q).tu = 0;
m = n = k = 1;
// 依次遍历M与N的三元组
while(m <= M.tu && n <= N.tu) {
// M中的三元组行下标较小
if(M.data[m].i < N.data[n].i) {
(*Q).data[k] = M.data[m];
m++;
// N中的三元组行下标较小
} else if(M.data[m].i > N.data[n].i) {
(*Q).data[k] = N.data[n];
n++;
// M与N中的三元组行下标一致,需要进一步比较列坐标
} else {
// M中的三元组列下标较小
if(M.data[m].j < N.data[n].j) {
(*Q).data[k] = M.data[m];
m++;
// N中的三元组列下标较小
} else if(M.data[m].j > N.data[n].j) {
(*Q).data[k] = N.data[n];
n++;
// M与N中的三元组列下标一致,需要进行加法运算
} else {
// 值已经加为0的话,不需要存储该元素
if((M.data[m].e + N.data[n].e) == 0) {
m++;
n++;
continue;
} else {
(*Q).data[k].i = M.data[m].i;
(*Q).data[k].j = M.data[m].j;
(*Q).data[k].e = M.data[m].e + N.data[n].e;
m++;
n++;
}
}
}
k++;
(*Q).tu++;
}
// 遍历M中剩余的三元组
while(m <= M.tu) {
(*Q).data[k] = M.data[m];
m++;
k++;
(*Q).tu++;
}
// 遍历N中剩余的三元组
while(n <= N.tu) {
(*Q).data[k] = N.data[n];
n++;
k++;
(*Q).tu++;
}
return OK;
}
/*
* 矩阵减法
*
* Q = M - N。
*/
Status SubSMatrix(TSMatrix M, TSMatrix N, TSMatrix* Q) {
int m, n, k;
if(M.mu != N.mu || M.nu != N.nu) {
printf("两矩阵的行数、列数不满足相减条件!!\n");
return ERROR;
}
// 初始化Q
(*Q).mu = M.mu;
(*Q).nu = M.nu;
(*Q).tu = 0;
m = n = k = 1;
// 依次遍历M与N的三元组
while(m <= M.tu && n <= N.tu) {
// M中的三元组行下标较小
if(M.data[m].i < N.data[n].i) {
(*Q).data[k] = M.data[m];
m++;
// N中的三元组行下标较小
} else if(M.data[m].i > N.data[n].i) {
(*Q).data[k].i = N.data[n].i;
(*Q).data[k].j = N.data[n].j;
(*Q).data[k].e = -N.data[n].e; // 由于是相减,所以要对元素值取相反数
n++;
// M与N中的三元组行下标一致,需要进一步比较列坐标
} else {
// M中的三元组列下标较小
if(M.data[m].j < N.data[n].j) {
(*Q).data[k] = M.data[m];
m++;
// N中的三元组列下标较小
} else if(M.data[m].j > N.data[n].j) {
(*Q).data[k].i = N.data[n].i;
(*Q).data[k].j = N.data[n].j;
(*Q).data[k].e = -N.data[n].e; // 由于是相减,所以要对元素值取相反数
n++;
// M与N中的三元组列下标一致,需要进行减法运算
} else {
// 值已经减为0的话,不需要存储该元素
if((M.data[m].e - N.data[n].e) == 0) {
m++;
n++;
continue;
} else {
(*Q).data[k].i = M.data[m].i;
(*Q).data[k].j = M.data[m].j;
(*Q).data[k].e = M.data[m].e - N.data[n].e;
m++;
n++;
}
}
}
k++;
(*Q).tu++;
}
// 遍历M中剩余的三元组
while(m <= M.tu) {
(*Q).data[k] = M.data[m];
m++;
k++;
(*Q).tu++;
}
// 遍历N中剩余的三元组
while(n <= N.tu) {
(*Q).data[k].i = N.data[n].i;
(*Q).data[k].j = N.data[n].j;
(*Q).data[k].e = -N.data[n].e;
n++;
k++;
(*Q).tu++;
}
return OK;
}
/*
* 矩阵乘法
*
* Q = M * N,这里实现的是传统矩阵乘法。
*/
Status MultSMatrix(TSMatrix M, TSMatrix N, TSMatrix* Q) {
int m, n, i, j, k;
ElemType c, c1, c2;
// M的列数需要等于N的行数
if(M.nu != N.mu) {
printf("两矩阵的行数、列数不满足相乘条件!!\n");
return ERROR;
}
// 初始化Q
(*Q).mu = M.mu;
(*Q).nu = N.nu;
(*Q).tu = 0;
// 如果存在零矩阵
if(M.tu * N.tu == 0) {
return OK;
}
// 遍历矩阵M的行
for(i = 1; i <= M.mu; i++) {
// 遍历矩阵N的列
for(j = 1; j <= N.nu; j++) {
c = 0;
for(k = 1; k <= M.nu; k++) {
// 记录M[i][k]的值
c1 = 0;
// 依次寻找位于指定位置的M三元组
for(m = 1; m <= M.tu; m++) {
if(M.data[m].i == i && M.data[m].j == k) {
c1 = M.data[m].e;
break;
}
}
// 记录N[k][j]的值
c2 = 0;
//依次寻找位于指定位置的N三元组
for(n = 1; n <= N.tu; n++) {
if(N.data[n].i == k && N.data[n].j == j) {
c2 = N.data[n].e;
break;
}
}
// 计算Q[i][j]的值
if(c1 && c2) {
c += c1 * c2;
}
}
// 如果计算结果不为0,则进行存储
if(c != 0) {
(*Q).tu++;
(*Q).data[(*Q).tu].i = i;
(*Q).data[(*Q).tu].j = j;
(*Q).data[(*Q).tu].e = c;
}
}
}
return OK;
}
/*
* ████████ 算法5.1 ████████
*
* 矩阵转置
*/
Status TransposeSMatrix(TSMatrix M, TSMatrix* T) {
int p, q, col;
(*T).mu = M.nu;
(*T).nu = M.mu;
(*T).tu = M.tu;
if((*T).tu != 0) {
q = 1; // q用于T中非零元的计数
// col代表M的列,T的行
for(col = 1; col <= M.nu; ++col) {
// 在M中查找第j列的元素,依次将其转置到T中
for(p = 1; p <= M.tu; ++p) {
if(M.data[p].j == col) {
(*T).data[q].i = M.data[p].j; // M的列变为T的行
(*T).data[q].j = M.data[p].i; // M的行变为T的列
(*T).data[q].e = M.data[p].e; // 每个三元组值不变
++q;
}
}
}
}
return OK;
}
/*
* ████████ 算法5.2 ████████
*
* 矩阵快速转置
*/
Status FastTransposeSMatrix(TSMatrix M, TSMatrix* T) {
int col, t, p, q;
int* num; // num[col] 表示M第col列中非零元的个数
int* copt; // copt[col]表示M第col列第一个非零元在转置后矩阵中的位置
(*T).mu = M.nu;
(*T).nu = M.mu;
(*T).tu = M.tu;
// 提前返回
if((*T).tu == 0) {
return ERROR;
}
num = (int*) malloc(M.nu * sizeof(int));
copt = (int*) malloc(M.nu * sizeof(int));
// 初始化数组num
for(col = 1; col <= M.nu; ++col) {
num[col] = 0;
}
// 统计M中的非零元,统计每列非零元的个数
for(t = 1; t <= M.tu; ++t) {
num[M.data[t].j]++;
}
// 第1列第1个非零元总是位于转置后矩阵中的首位
copt[1] = 1;
// 计算各列第1个非零元在转置矩阵中的位置
for(col = 2; col <= M.nu; ++col) {
copt[col] = copt[col - 1] + num[col - 1];
}
// 依次扫描M中的三元组
for(p = 1; p <= M.tu; ++p) {
col = M.data[p].j; // 计算当前非零元所处的列
q = copt[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;
++copt[col]; // 再遇到此列元素时,其在转置矩阵中的位置应当增一(该步骤很重要)
}
return OK;
}
/*
* 输出矩阵
*/
void PrintSMatrix(TSMatrix M) {
int r, c;
int k = 1;
for(r = 1; r <= M.mu; r++) {
for(c = 1; c <= M.nu; c++) {
if(r == M.data[k].i && c == M.data[k].j) {
printf("%3d ", M.data[k].e);
k++;
} else {
printf("%3d ", 0);
}
}
printf("\n");
}
}
+104
View File
@@ -0,0 +1,104 @@
/*=======================
* 三元组顺序表(稀疏矩阵)
*
* 包含算法: 5.1、5.2
========================*/
#ifndef TSMATRIX_H
#define TSMATRIX_H
#include <stdio.h>
#include <stdlib.h> // 提供 malloc 原型
#include <string.h> // 提供 strstr 原型
#include "Status.h" //**▲01 绪论**//
/* 宏定义 */
#define MAXSIZE 12500 // 非零元数量的最大值
/* 三元组稀疏矩阵元素类型 */
typedef int ElemType;
/* 三元组类型定义,主要用来存储非零元 */
typedef struct {
int i, j; // 该三元组非零元的行下标和列下标
ElemType e;
} Triple;
/* 三元组稀疏矩阵类型定义 */
typedef struct {
Triple data[MAXSIZE + 1]; // 非零元三元组表,data[0]未用
int mu, nu, tu; // 矩阵的行数、列数和非零元个数
} TSMatrix;
/*
* 创建稀疏矩阵M
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateSMatrix(TSMatrix* M, char* path);
/*
* 销毁稀疏矩阵
*
*【注】
* 三元组顺序表的结构无法销毁。
*/
Status DestroySMatrix(TSMatrix* M);
/*
* 矩阵复制
*
* 创建一个新矩阵T,该矩阵包含了从矩阵M中包含的数据。
*/
Status CopySMatrix(TSMatrix M, TSMatrix* T);
/*
* 矩阵加法
*
* Q = M + N。
*/
Status AddSMatrix(TSMatrix M, TSMatrix N, TSMatrix* Q);
/*
* 矩阵减法
*
* Q = M - N。
*/
Status SubSMatrix(TSMatrix M, TSMatrix N, TSMatrix* Q);
/*
* 矩阵乘法
*
* Q = M * N,这里实现的是传统矩阵乘法。
*/
Status MultSMatrix(TSMatrix M, TSMatrix N, TSMatrix* Q);
/*
* ████████ 算法5.1 ████████
*
* 矩阵转置
*/
Status TransposeSMatrix(TSMatrix M, TSMatrix* T);
/*
* ████████ 算法5.2 ████████
*
* 矩阵快速转置
*/
Status FastTransposeSMatrix(TSMatrix M, TSMatrix* T);
/*
* 输出矩阵
*/
void PrintSMatrix(TSMatrix M);
#endif
+4
View File
@@ -0,0 +1,4 @@
行数:5
列数:5
非零元个数:10
三元组:(1,2,1),(1,4,5),(2,3,-3),(2,5,2),(3,1,2),(3,2,3),(3,3,4),(4,4,2),(5,1,3),(5,2,-1)
+4
View File
@@ -0,0 +1,4 @@
行数:5
列数:5
非零元个数:8
三元组:(1,1,-3)(1,3,2)(2,4,-1)(3,2,4)(4,1,6)(4,5,5)(5,1,3)(5,3,2)
+52
View File
@@ -0,0 +1,52 @@
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
#include "RLSMatrix.h" //**▲05 数组和广义表**//
/*
* 获取矩阵中第i行第j列的元素,并将其存储到e中
*/
Status Algo_5_23(RLSMatrix M, int i, int j, int* e);
int main(int argc, char* argv[]) {
RLSMatrix M;
int e;
printf("█ 创建个稀疏矩阵 M ...\n");
CreateSMatrix(&M, "TestData_M.txt");
printf("M = \n");
PrintSMatrix(M);
Algo_5_23(M, 2, 3, &e);
printf("█ 第 %d 行 %d 列的元素为 %d\n", 2, 3, e);
return 0;
}
/*
* 获取矩阵中第i行第j列的元素,并将其存储到e中
*/
Status Algo_5_23(RLSMatrix M, int i, int j, int* e) {
int begin, end, k;
if(i < 1 || i > M.mu || j < 1 || j > M.nu) {
return ERROR;
}
// 获取第i行中首个非零元在三元组表中的位置
begin = M.rpos[i];
end = (i == M.mu ? M.tu : M.rpos[i + 1] - 1);
*e = 0; // 默认为0
for(k = begin; k <= end; k++) {
// 找到对应列下标的元素
if(M.data[k].j == j) {
*e = M.data[k].e;
break;
}
}
return OK;
}
+13
View File
@@ -0,0 +1,13 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(05.23 RLSMatrix.h RLSMatrix.c 05.23.c)
# 链接公共库
target_link_libraries(05.23 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
File diff suppressed because it is too large Load Diff
+107
View File
@@ -0,0 +1,107 @@
/*=============================
* 行逻辑链接的顺序表(稀疏矩阵)
*
* 包含算法: 5.3
==============================*/
#ifndef RLSMATRIX_H
#define RLSMATRIX_H
#include <stdio.h>
#include <stdlib.h> // 提供 malloc 原型
#include <string.h> // 提供 strstr 原型
#include "Status.h" //**▲01 绪论**//
/* 宏定义 */
#define MAXSIZE 12500 // 非零元数量的最大值
#define MAXRC 20 // 各行元素个数的最大值
/* 行逻辑链接的稀疏矩阵元素类型 */
typedef int ElemType;
/* 三元组类型定义,主要用来存储非零元 */
typedef struct {
int i, j; // 该非零元的行下标和列下标
ElemType e;
} Triple;
/* 行逻辑链接的稀疏矩阵类型定义 */
typedef struct {
Triple data[MAXSIZE + 1]; // 非零元三元组表,data[0]未用
int rpos[MAXRC + 1]; // 各行第一个非零元在三元组表中的位置表,rpos[0]未用
int mu, nu, tu; // 矩阵的行数、列数和非零元个数
} RLSMatrix;
/*
* 创建稀疏矩阵M
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateSMatrix(RLSMatrix* M, char* path);
/*
* 销毁稀疏矩阵
*
*【注】
* 行逻辑链接的顺序表结构无法销毁。
*/
Status DestroySMatrix(RLSMatrix* M);
/*
* 矩阵复制
*
* 创建一个新矩阵T,该矩阵包含了从矩阵M中包含的数据。
*/
Status CopySMatrix(RLSMatrix M, RLSMatrix* T);
/*
* 矩阵加法
*
* Q = M + N。
*/
Status AddSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix* Q);
/*
* 矩阵减法
*
* Q = M - N。
*/
Status SubSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix* Q);
/*
* ████████ 算法5.3 ████████
*
* 矩阵乘法
*
* Q = M * N。
*/
Status MultSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix* Q);
/*
* 矩阵转置
*/
Status TransposeSMatrix(RLSMatrix M, RLSMatrix* T);
/*
* 矩阵快速转置
*/
Status FastTransposeSMatrix(RLSMatrix M, RLSMatrix* T);
/*
* 输出矩阵
*/
void PrintSMatrix(RLSMatrix M);
// 为rpos数组赋值
static void AssignRpos(RLSMatrix* M);
#endif
+4
View File
@@ -0,0 +1,4 @@
行数:5
列数:5
非零元个数:10
三元组:(1,2,1),(1,4,5),(2,3,-3),(2,5,2),(3,1,2),(3,2,3),(3,3,4),(4,4,2),(5,1,3),(5,2,-1)
+49
View File
@@ -0,0 +1,49 @@
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
#include "SMatrix.h" //**稀疏矩阵**//
/*
* 获取矩阵中第i行第j列的元素,并将其存储到e中
*/
Status Algo_5_24(SMatrix M, int i, int j, int* e);
int main(int argc, char* argv[]) {
SMatrix M;
int e;
printf("█ 创建个稀疏矩阵 M ...\n");
CreateSMatrix(&M, "TestData_M.txt");
printf("M = \n");
PrintSMatrix(M);
Algo_5_24(M, 2, 3, &e);
printf("第 %d 行 %d 列的元素为 %d\n", 2, 3, e);
return 0;
}
/*
* 获取矩阵中第i行第j列的元素,并将其存储到e中
*/
Status Algo_5_24(SMatrix M, int i, int j, int* e) {
int s, p;
if(i < 1 || i > M.mu || j < 1 || j > M.nu) {
return ERROR;
}
for(p = 1, s = (i - 1) * M.nu + j; M.data[p].seq < s; p++) {
// 寻找指定的元素
}
*e = 0; // 默认为0
// 找到对应列下标的元素
if(M.data[p].seq == s) {
*e = M.data[p].e;
}
return OK;
}
+13
View File
@@ -0,0 +1,13 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(05.24 SMatrix.h SMatrix.c 05.24.c)
# 链接公共库
target_link_libraries(05.24 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+44
View File
@@ -0,0 +1,44 @@
/*======================
* 稀疏矩阵,用于习题5.24
=======================*/
#include "SMatrix.h" //**稀疏矩阵**//
// 创建稀疏矩阵M
Status CreateSMatrix(SMatrix* M, char* path) {
FILE* fp;
int k, i, j;
fp = fopen(path, "r");
ReadData(fp, "%d%d%d", &((*M).mu), &((*M).nu), &((*M).tu));
// 读取元素
for(k = 1; k <= (*M).tu; k++) {
ReadData(fp, "%d%d%d", &i, &j, &((*M).data[k].e));
(*M).data[k].seq = (i - 1) * (*M).nu + j;
}
fclose(fp);
return OK;
}
// 输出稀疏矩阵M
void PrintSMatrix(SMatrix M) {
int r, c;
int k = 1;
for(r = 1; r <= M.mu; r++) {
for(c = 1; c <= M.nu; c++) {
if(r == (M.data[k].seq - 1) / M.nu + 1 && c == (M.data[k].seq - 1) % M.nu + 1) {
printf("%3d ", M.data[k].e);
k++;
} else {
printf(" 0 ");
}
}
printf("\n");
}
}
+32
View File
@@ -0,0 +1,32 @@
/*======================
* 稀疏矩阵,用于习题5.24
=======================*/
#ifndef SMATRIX_H
#define SMATRIX_H
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
#define MAXSIZE 100 // 假设非零元个数的最大值为400
/* 非零元类型 */
typedef struct {
int seq; // 该非零元在矩阵中的序号(以行序为主序)
int e;
} SElem;
/* 稀疏矩阵 */
typedef struct {
SElem data[MAXSIZE + 1]; // 存储各非零元素,data[0]未用
int mu, nu, tu; // 矩阵的行数、列数和非零元个数
} SMatrix;
// 创建稀疏矩阵M
Status CreateSMatrix(SMatrix* M, char* path);
// 输出稀疏矩阵M
void PrintSMatrix(SMatrix M);
#endif
+4
View File
@@ -0,0 +1,4 @@
行数:5
列数:5
非零元个数:10
三元组:(1,2,1),(1,4,5),(2,3,-3),(2,5,2),(3,1,2),(3,2,3),(3,3,4),(4,4,2),(5,1,3),(5,2,-1)
+79
View File
@@ -0,0 +1,79 @@
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
#include "SMatrix.h" //**稀疏矩阵**//
/*
* 稀疏矩阵加法:AddSMatrix
*/
Status Algo_5_25(SMatrix P, SMatrix Q, SMatrix* R);
int main(int argc, char* argv[]) {
SMatrix M, N, Q;
printf("█ 创建两个稀疏矩阵 M、N ...\n");
CreateSMatrix(&M, "TestData_M.txt");
CreateSMatrix(&N, "TestData_N.txt");
printf("█ M = \n");
PrintSMatrix(M);
printf("█ N = \n");
PrintSMatrix(N);
Algo_5_25(M, N, &Q);
printf("Q = M + N = \n");
PrintSMatrix(Q);
return 0;
}
/*
* 稀疏矩阵加法:AddSMatrix
*/
Status Algo_5_25(SMatrix P, SMatrix Q, SMatrix* R) {
int i, j;
int p, q, r;
if(P.mu != Q.mu || P.nu != Q.nu) {
printf("两矩阵的行数、列数不满足相加条件!!\n");
return ERROR;
}
// 初始化R的信息
(*R).mu = P.mu;
(*R).nu = P.nu;
(*R).tu = 0;
memset((*R).V, 0, sizeof((*R).V));
memset((*R).B, 0, sizeof((*R).B));
// 指向P、Q、R中的数组V
p = q = r = 0;
for(i = 0; i < P.mu; ++i) {
for(j = 0; j < P.nu; ++j) {
if(P.B[i][j] == 0 && Q.B[i][j] == 0) {
continue;
} else if(P.B[i][j] == 0 && Q.B[i][j] == 1) {
(*R).V[r++] = Q.V[q++];
(*R).B[i][j] = 1;
} else if(P.B[i][j] == 1 && Q.B[i][j] == 0) {
(*R).V[r++] = P.V[p++];
(*R).B[i][j] = 1;
// 如果P、Q两处均有非零元,则尝试相加
} else {
if((P.V[p] + Q.V[q])!=0) {
(*R).V[r++] = P.V[p] + Q.V[q];
(*R).B[i][j] = 1;
}
p++;
q++;
}
}
}
(*R).tu = r;
return OK;
}
+13
View File
@@ -0,0 +1,13 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(05.25 SMatrix.h SMatrix.c 05.25.c)
# 链接公共库
target_link_libraries(05.25 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+48
View File
@@ -0,0 +1,48 @@
/*======================
* 稀疏矩阵,用于习题5.25
=======================*/
#include "SMatrix.h" //**稀疏矩阵**//
// 创建稀疏矩阵M
Status CreateSMatrix(SMatrix* M, char* path) {
FILE* fp;
int v, i, j;
fp = fopen(path, "r");
ReadData(fp, "%d%d%d", &((*M).mu), &((*M).nu), &((*M).tu));
memset((*M).V, 0, sizeof((*M).V));
memset((*M).B, 0, sizeof((*M).B));
for(v=0; v < (*M).tu; v++) {
// 读取非零元信息,将元素存入数组V中
ReadData(fp, "%d%d%d", &i, &j, &((*M).V[v]));
(*M).B[i-1][j-1] = 1;
}
fclose(fp);
return OK;
}
// 输出稀疏矩阵M
void PrintSMatrix(SMatrix M) {
int v, i, j;
v = 0; // 遍历V的游标
for(i = 1; i <= M.mu; i++) {
for(j = 1; j <= M.nu; j++) {
if(M.B[i-1][j-1] == 1) {
printf("%3d ", M.V[v++]);
} else {
printf("%3d ", M.B[i-1][j-1]);
}
}
printf("\n");
}
}
+32
View File
@@ -0,0 +1,32 @@
/*======================
* 稀疏矩阵,用于习题5.25
=======================*/
#ifndef SMATRIX_H
#define SMATRIX_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Status.h" //**▲01 绪论**//
/* 宏定义 */
#define Mu 20 // 假设矩阵行数最大值为20
#define Nu 20 // 假设矩阵列数最大值为20
#define MAXSIZE 400 // 假设非零元个数的最大值为400
/* 稀疏矩阵类型定义 */
typedef struct {
int V[MAXSIZE]; // 存储矩阵的元素
int B[Mu][Nu]; // 标记矩阵中各位置元素是否为非零元
int mu, nu, tu; // 矩阵行数,列数,非零元个数
} SMatrix;
// 创建稀疏矩阵M
Status CreateSMatrix(SMatrix* M, char* path);
// 输出稀疏矩阵M
void PrintSMatrix(SMatrix M);
#endif
+4
View File
@@ -0,0 +1,4 @@
行数:5
列数:5
非零元个数:10
三元组:(1,2,1),(1,4,5),(2,3,-3),(2,5,2),(3,1,2),(3,2,3),(3,3,4),(4,4,2),(5,1,3),(5,2,-1)
+4
View File
@@ -0,0 +1,4 @@
行数:5
列数:5
非零元个数:8
三元组:(1,1,-3)(1,3,2)(2,4,-1)(3,2,4)(4,1,6)(4,5,5)(5,1,3)(5,3,2)
+49
View File
@@ -0,0 +1,49 @@
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
#include "CrossList.h" //**▲05 数组和广义表**//
/*
* 以三元组形式输出十字链表
*/
Status Algo_5_26(CrossList M);
int main(int argc, char* argv[]) {
CrossList M;
printf("创建十字链表 M...\n");
CreateSMatrix(&M, "TestData_M.txt");
printf("M = \n");
PrintSMatrix(M);
printf("按三元组形式输出 M...\n");
printf(" 行 列 值\n");
Algo_5_26(M);
return 0;
}
/*
* 以三元组形式输出十字链表
*/
Status Algo_5_26(CrossList M) {
int i, j;
OLNode* p;
if(M.tu==0) {
return ERROR;
}
for(i = 1; i <= M.mu; ++i) {
p = M.rhead[i];
for(j = 1; j <= M.nu; ++j) {
if(p && p->j == j) {
printf("(%2d %2d %3d)\n", i, j, p->e);
p = p->right;
}
}
}
return OK;
}
+13
View File
@@ -0,0 +1,13 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(05.26 CrossList.h CrossList.c 05.26.c)
# 链接公共库
target_link_libraries(05.26 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
File diff suppressed because it is too large Load Diff
+94
View File
@@ -0,0 +1,94 @@
/*===================
* 十字链表(稀疏矩阵)
*
* 包含算法: 5.4
====================*/
#ifndef CROSSLIST_H
#define CROSSLIST_H
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include <string.h> // 提供 strstr 原型
#include "Status.h" //**▲01 绪论**//
/* 十字链表元素类型 */
typedef int ElemType;
/* 非零元类型定义 */
typedef struct OLNode {
int i, j; // 该非零元的行下标和列下标
ElemType e;
struct OLNode* right; // 该非零元所在的行表的后继链域
struct OLNode* down; // 该非零元所在的列表的后继链域
} OLNode, * OLink;
/* 十字链表类型定义 */
typedef struct {
OLink* rhead; // 行链表头指针
OLink* chead; // 列链表头指针
int mu, nu, tu; // 矩阵的行数、列数和非零元个数
} CrossList;
/*
* ████████ 算法5.4 ████████
*
* 创建稀疏矩阵M
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateSMatrix(CrossList* M, char* path);
/*
* 销毁稀疏矩阵
*/
Status DestroySMatrix(CrossList* M);
/*
* 矩阵复制
*
* 创建一个新矩阵T,该矩阵包含了从矩阵M中包含的数据。
*/
Status CopySMatrix(CrossList M, CrossList* T);
/*
* 矩阵加法
*
* Q = M + N。
*/
Status AddSMatrix(CrossList M, CrossList N, CrossList* Q);
/*
* 矩阵减法
*
* Q = M - N。
*/
Status SubSMatrix(CrossList M, CrossList N, CrossList* Q);
/*
* 矩阵乘法
*
* Q = M * N。
*/
Status MultSMatrix(CrossList M, CrossList N, CrossList* Q);
/*
* 矩阵转置
*/
Status TransposeSMatrix(CrossList M, CrossList* T);
/*
* 输出矩阵
*/
void PrintSMatrix(CrossList M);
#endif
+4
View File
@@ -0,0 +1,4 @@
行数:5
列数:5
非零元个数:10
三元组:(1,2,1),(1,4,5),(2,3,-3),(2,5,2),(3,1,2),(3,2,3),(3,3,4),(4,4,2),(5,1,3),(5,2,-1)
+41
View File
@@ -0,0 +1,41 @@
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
#include "CrossList.h" //**▲05 数组和广义表**//
/*
* 稀疏矩阵加法:AddSMatrix
*
*【注】
* 该函数已在CrossList相关文件中定义
*/
Status Algo_5_27(CrossList M, CrossList N, CrossList* Q);
int main(int argc, char* argv[]) {
CrossList M, N, Q;
printf("█ 创建两个稀疏矩阵 M、N ...\n");
CreateSMatrix(&M, "TestData_M.txt");
CreateSMatrix(&N, "TestData_N.txt");
printf("█ M = \n");
PrintSMatrix(M);
printf("█ N = \n");
PrintSMatrix(N);
Algo_5_27(M, N, &Q);
printf("█ Q = M + N = \n");
PrintSMatrix(Q);
return 0;
}
/*
* 稀疏矩阵加法:AddSMatrix
*
*【注】
* 该函数已在CrossList相关文件中定义
*/
Status Algo_5_27(CrossList M, CrossList N, CrossList* Q) {
return AddSMatrix(M, N, Q);
}

Some files were not shown because too many files have changed in this diff Show More