mirror of
https://github.com/kangjianwei/Data-Structure.git
synced 2026-08-18 01:10:14 +08:00
💡 <05 数据和广义表>习题代码
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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})
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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})
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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})
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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})
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
Reference in New Issue
Block a user