数组、矩阵和广义表
数组的定义、稀疏矩阵压缩存储、三元组、加法、乘法、矩阵转置、矩阵快速转置
VA_LIST应用说明
链接: [link]https://blog.csdn.net/ZKR_HN/article/details/99558135
VA_LIST 是在C语言中解决变参问题的一组宏,变参问题是指参数的个数不定,可以是传入一个参数也可以是多个;可变参数中的每个参数的类型可以不同,也可以相同;可变参数的每个参数并没有实际的名称与之相对应,用起来是很灵活。
1
其中va_list( VA_LIST 是在C语言中解决变参问题的一组宏):va_list表示可变参数列表类型,实际上就是一个char指针fmt。
下面是va_list的用法示例
VA_LIST的用法:
(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;
(2)然后用VA_START宏初始化变量刚定义的VA_LIST变量;
(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数);
(4)最后用VA_END宏结束可变参数的获取。
上面是va_list的具体用法,下面讲解一下va_list各个语句含义(如上示例黑体部分)和va_list的实现。
可变参数是由宏实现的,但是由于硬件平台的不同,编译器的不同,宏的定义也不相同,下面是VC6.0中x86平台的定义:
typedef char * va_list; // TC中定义为void*
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) //为了满足需要内存对齐的系统
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //ap指向第一个变参的位置,即将第一个变参的地址赋予ap
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) /获取变参的具体内容,t为变参的类型,如有多个参数,则通过移动ap的指针来获得变参的地址,从而获得内容/
#define va_end(ap) ( ap = (va_list)0 ) //清空va_list,即结束变参的获取
C语言的函数形参是从右向左压入堆栈的,以保证栈顶是第一个参数,而且x86平台内存分配顺序是从高地址到低地址。因此似函数AVEInt(int var1,int
var2,…,int varN)内存分配大致上是这样的:(可变参数在中间)
va_list ap; 定义一个va_list变量ap
va_start(ap,v);执行ap = (va_list)&v + _INTSIZEOF(v),ap指向参数v之后的那个参数的地址,即ap指向第一个可变参数在堆栈的地址。
va_arg(ap,t) , ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )取出当前ap指针所指的值,并使ap指向下一个参数。
ap+= sizeof(t类型),让ap指向下一个参数的地址。然后返回ap-sizeof(t类型)的t类型指针,这正是第一个可变参数在堆栈里的地址。然后
用取得这个地址的内容。
va_end(ap); 清空va_list ap。
使用VA_LIST应该注意的问题:
(1)因为va_start, va_arg,
va_end等定义成宏,所以它显得很愚蠢,可变参数的类型和个数完全在该函数中由程序代码控制,它并不能智能地识别不同参数的个数和类型.
也就是说,你想实现智能识别可变参数的话是要通过在自己的程序里作判断来实现的.
(2)另外有一个问题,因为编译器对可变参数的函数的原型检查不够严格,对编程查错不利.不利于我们写出高质量的代码。
(3)由于参数的地址用于VA_START宏,所以参数不能声明为寄存器变量,或作为函数或数组类型。
数组的顺序存储表示
#include<stdarg.h>//标准头文件,提供宏va_start\va_arg和va_end,
//用于存取变长参数表
#include<iostream> //假设数组维数的最大值为8
using namespace std;
#define ERROR 0;
#define OK 1;
typedef int Status;
typedef int ElemType;
typedef int Boolean;
#define MAX_ARRAY_DIM 8
typedef struct {
ElemType* base; //数组元素基址,由InitArray分配
int dim; //数组维数
int* bounds; //数组维界基址,由InitArray分配
int* constants; //数组映像函数常量基址,由InitArray分配
}Array;
//--------基本操作的函数原型说明--------
Status InitArray(Array& A, int dim,...);
//若维数dim和随后的各位长度合法,则构造相应的数组A,并返回OK
Status DestroyArray(Array& A);
//销毁数组A
Status Value(Array A, ElemType& e, ...);
//A是n维数组,e为元素变量,随后是n个下标值
//若各下标不超界,则e赋值所指定的A的元素值,并返回OK
Status Assign(Array& A, ElemType e, ...);
//A是n维数组,e为元素变量,随后是n个下标值
//若下标不超界,则将e的值赋给所指定的A元素,并返回OK
//-----基本操作的算法描述-----
Status InitArray(Array* A, int dim, ...)
{//若维数和各维长度合法,则构造相应的数组A,并返回OK
va_list ap;
if (dim<1 || dim>MAX_ARRAY_DIM)
return ERROR;
(*A).dim = dim;
(*A).bounds = (int*)malloc(dim * sizeof(int));
if (!(*A).bounds)
exit(OVERFLOW);
//若各维度长度合法,则存入A.bounds,并求出A的元素总数elemtotal
int elemtotal = 1;
va_start(ap, dim);
for (int i = 0; i < dim; ++i)
{
(*A).bounds[i] = va_arg(ap, int); //存入维度数
if ((*A).bounds[i] < 0)return 0;
elemtotal *= (*A).bounds[i]; //计算元素总数
}
va_end(ap);
(*A).base = (ElemType*)malloc(elemtotal * sizeof(ElemType));//基址
if (!(*A).base)exit(OVERFLOW);
(*A).constants = (int*)malloc(dim * sizeof(int));
if (!(*A).constants)
exit(OVERFLOW);
(*A).constants[dim - 1] = 1; //L=1,指针的增减艺元素的大小为单位
for (int i = dim - 2; i >= 0; --i)
{
(*A).constants[i] = (*A).bounds[i + 1] * (*A).constants[i + 1];//每一维偏移常数
}
return OK;
}
Status DestroyArray(Array* A)
{//销毁数组A
if (!(*A).base)return ERROR;
free((*A).base);
(*A).base = NULL;
if (!(*A).bounds)
return ERROR;
free((*A).bounds);
(*A).bounds = NULL;
if (!(*A).constants)
return ERROR;
free((*A).constants);
(*A).constants = NULL;
return OK;
}
Status Locate(Array A, va_list ap, int* off)
{
//若ap指示的各下标值合法,则求出该元素在A中相对地址off
*off = 0;
for (int i = 0; i < A.dim; ++i)
{
int ind = va_arg(ap, int);
if (ind < 0 || ind >= A.bounds[i])
return OVERFLOW;
*off += A.constants[i] * ind; //偏移量
}
return OK;
}
Status Value(ElemType* e, Array A, ...) {
//A是n维数组,额为元素变量,随后是n个下标
//若各下标不超界,则e赋值为所指定的A的元素的值,并返回OK。
va_list ap;
Status result;
int off;
va_start(ap, A);
if ((result = Locate(A, ap, &off)) <= 0)
return result;
*e = *(A.base + off);
return OK;
}
Status Assign(Array* A, ElemType e, ...)
{
//A是n维数组,e为元素变量,随后是n个下标值
//若下标不超界,则将e的值赋给所指定的A的元素,并返回OK。
va_list ap;
Status result;
int off;
va_start(ap, e);
if ((result = Locate(*A, ap, &off)) <= 0)
return result;
*((*A).base + off) = e;
return OK;
}
int main()
{
Array A;
int i, j, k, * p,dim = 3, bound1 = 3, bound2 = 4, bound3 = 2;//a[3][4][2]
ElemType e, * p1;
InitArray(&A, dim, bound1, bound2, bound3);
p = A.bounds;
printf("A.bounds=");
for (i = 0; i < dim; i++)
{
printf("%d ", *(p + i));
}
p = A.constants;
printf("\nA.constants= ");
for (i = 0; i < dim; i++)
{
printf("%d ", *(p + i));
}
printf("\n%d页%d行%d列矩阵元素如下:\n", bound1, bound2, bound3);
for (i = 0; i < bound1; i++)
{
for (j = 0; j < bound2; j++)
{
for (k = 0; k < bound3; k++)
{
Assign(&A, i * 100 + j * 10 + k, i, j, k);//将i*100+j*10+k赋值给A[i][j][k]
Value(&e, A,i, j, k);//将A[i][j][k]值赋给e
printf("A[%d][%d][%d]=%2d ", i, j, k, e);
}
printf("\n");
}
printf("\n");
}
p1 = A.base;
printf("A.base=\n");
for (i = 0; i < bound1 * bound2 * bound3; i++)//顺序输出A.base
{
printf("%4d", *(p1 + i));
if (i % (bound2 * bound3) == bound2 * bound3 - 1)
printf("\n");
}
DestroyArray(&A);
return 0;
}
稀疏矩阵操作
#include<iostream>
using namespace std;
#define ERROR 0
#define OK 1
typedef int Status;
#define MAX 100
#define number 10
typedef struct {
int row, col;
int item;
}Triple;
class TripleMatrix {
private:
Triple data[MAX];
int mu, nu, tu;
public:
TripleMatrix();
TripleMatrix(int m, int n, int num);
Status getItem(int row, int col);
Status setItem(int row, int col, int items);
void printTriple();
void printMatrix();
void inputMatrix(int m, int n, int num);
friend bool MatrixAdd(TripleMatrix A, TripleMatrix B, TripleMatrix& result);
friend bool MatrixMul(TripleMatrix A, TripleMatrix B, TripleMatrix& result);
friend Status TransposeSMatrix(TripleMatrix M, TripleMatrix& T);
friend Status FastTransposeSMatrix(TripleMatrix M, TripleMatrix& T);
friend Status fastTransposeMatrix(TripleMatrix M, TripleMatrix& T);
};
TripleMatrix::TripleMatrix()
{
mu = 0;
nu = 0;
tu = 0;
for (int i = 0; i < MAX; i++)
data[i] = { 0,0,0 };
}
TripleMatrix::TripleMatrix(int m, int n, int num)
{
mu = m;
nu = n;
tu = 0;
for (int i = 0; i < number; i++)
data[i] = { 0,0,0 };
}
Status TripleMatrix::setItem(int row, int col, int items)
{
if (row > mu || col > nu)
return ERROR;
if (tu == MAX)
return ERROR;
if (items == 0)
return OK;
int index=1;
while (index <= tu)
{
if (row > data[index].row)
index++;
else if (row == data[index].row && col > data[index].col)
index++;
else
break;
}
if (row == data[index].row && col == data[index].col)
data[index].item = items;
else
{
for (int i = tu; i > index; i--)
{
data[i].row = data[i - 1].row;
data[i].col = data[i - 1].col;
data[i].item = data[i - 1].item;
}
data[index].row = row;
data[index].col = col;
data[index].item = items;
tu++;
}
return OK;
}
Status TripleMatrix::getItem(int row, int col)
{
int i;
if (row > mu || col > nu)
return ERROR;
for (i = 1; i <=tu; i++)
if (row == data[i].row && col == data[i].col)
return data[i].item;
return 0;
}
void TripleMatrix::printTriple()
{
int i;
printf("打印三元数组:\n");
printf("row\tcol\titem\n");
for (i = 1; i <=tu; i++)
printf("%d\t%d\t%d\n", data[i].row, data[i].col, data[i].item);
}
void TripleMatrix::printMatrix()
{
int i, j, tripleindex =1;
printf("打印矩阵:\n");
printf("row\tcol\titem\n");
for (i = 1; i <= mu; i++)
{
for (j = 1; j <= nu; j++)
{
if (i == data[tripleindex].row && j == data[tripleindex].col)
{
cout << data[tripleindex].item << "\t";
tripleindex++;
}
else
cout << "0\t";
}
cout << endl;
}
cout << "矩阵有" << mu << "行" << nu << "列, " << "共" << tu<<" 个数据"<< endl;
return;
}
void TripleMatrix::inputMatrix(int m, int n, int num)
{
int row, col, Item;
for (int i = 1; i <= num; i++)
{
cout << "请输入行,列,非零元素:" ;
cin >> row >> col >> Item ;
if (Item != 0)
{
if (setItem(row, col, Item) == ERROR)
{
cout << "行号列号不正确,或者三元组数组满,不能正确存储!";
break;
}
}
}
}
//矩阵加法
bool MatrixAdd(TripleMatrix A, TripleMatrix B, TripleMatrix& result)
{
if (A.mu != B.mu || A.nu != B.nu)
return ERROR;
for (int i =1; i <=A.mu; i++)
{
for (int j =1; j <=A.nu; j++)
{
int item = A.getItem(i, j) +B.getItem(i, j);
//如果计算出来的值不为0,则插入到稀疏矩阵中
if (item != 0)
result.setItem(i, j, item);
}
}
return true;
}
//矩阵乘法
bool MatrixMul(TripleMatrix A, TripleMatrix B, TripleMatrix& result)
{
int i, j, k;
if (A.nu != B.mu)
return ERROR;
result.mu = A.mu;
result.nu = B.nu;
for (i = 1; i <= A.mu; i++)
{
for (j = 1; j <= B.nu; j++) {
int sum = 0;
for (k = 1; k <= A.nu; k++)
{
if (A.getItem(i, k) == 0 || B.getItem(k, j) == 0)//如果矩阵中的值为0,则乘积为0
sum += 0;
else
sum += A.getItem(i, k) * B.getItem(k, j);
}
if (sum != 0)
result.setItem(i, j,sum);
}
}
return true;
}
//矩阵转置运算
Status TransposeSMatrix(TripleMatrix M, TripleMatrix& T)
{
int q, col, p;;
T.mu = M.nu;
T.nu = M.mu;
T.tu = M.tu;
if (T.tu)
{
q = 1;
for (col = 1; col <=M.nu; col++)
{
for(p=1;p<=M.tu;p++)
if (M.data[p].col == col)
{
T.data[q].row = M.data[p].col;
T.data[q].col = M.data[p].row;
T.data[q].item = M.data[p].item;
++q;
}
}
}
return OK;
}
//矩阵快速转置运算
Status FastTransposeSMatrix(TripleMatrix M, TripleMatrix& T)
{
int col, t, p, q, num[10], cpot[10];
T.mu = M.nu;
T.nu = M.mu;
T.tu = M.tu;
if (T.tu)
{
//cpot[0] = 0;
for (col = 1; col <= M.nu; ++col)
num[col] = 0;
for (t = 1; t <= M.tu; ++t)
num[M.data[t].col]++;
cpot[1] = 1;
//求第col列中第一个非零元在b.data中的序号
for (col = 2; col <= M.nu; ++col)
cpot[col] = cpot[col - 1] + num[col - 1];
for (p = 1; p <= M.tu; ++p) {
col = M.data[p].col;
q = cpot[col];
T.data[q].row = M.data[p].col;
T.data[q].col = M.data[p].row;
T.data[q].item = M.data[p].item;
++cpot[col];
}
}
return OK;
}//FastTransposeSMatrix
//矩阵快速转置运算2
Status fastTransposeMatrix(TripleMatrix M, TripleMatrix &T){
T.mu=M.nu;
T.nu=M.mu;
T.tu=M.tu;
if (T.tu) {
int array[number];
for (int col=1; col<=M.mu; col++) {
array[col]=0;
}
for (int t=1; t<=M.tu; t++) {
int j=M.data[t].col;
array[j]++;
}
int cpot[number];
cpot[1]=1;
for (int col=2; col<=M.mu; col++) {
cpot[col]=cpot[col-1]+array[col-1];
}
for (int p=1; p<=M.tu; p++) {
int col=M.data[p].col;
int q=cpot[col];
T.data[q].col = M.data[p].row;
T.data[q].row=M.data[p].col;
T.data[q].item=M.data[p].item;
cpot[col]++;
}
}
return true;
}
int main()
{
int m, n, num;
int numb;
cout << "*************************************************\n";
cout << "1>1:矩阵加法运算\t\t2>2:矩阵乘法运算\n";
cout << "3>3:矩阵转置运算\t\t4>4:矩阵快速转置运算\n ";
cout << "5>5:矩阵快速转置运算2\n ";
cout << "*************************************************\n";
cout << "请输入序号选择需要对矩阵进行的操作:";
cout << endl;
cin >> numb;
cout << "请输入第一矩阵的行列数和非零元素个数";
cin >> m >> n >> num;
TripleMatrix TripleA(m, n, num);
TripleA.inputMatrix(m, n, num);
TripleA.printTriple();
TripleA.printMatrix();
TripleMatrix TripleB;
while (numb != 1 && numb != 2 && numb !=3 && numb != 4 && numb != 5)
{
cout << "输入错误请重新输入!";
cin >> numb;
}
switch (numb)
{
case 1: //加法运算
{
cout << "请输入第二个矩阵的行列数和非零元素个数";
cin >> m >> n >> num;
TripleMatrix TripleB(m, n, num);
TripleB.inputMatrix(m, n, num);
TripleB.printTriple();
TripleB.printMatrix();
TripleMatrix TripleC(m,n,num);
MatrixAdd(TripleA, TripleB, TripleC);
TripleC.printTriple();
TripleC.printMatrix();
}
break;
case 2: //乘法运算
{
cout << "请输入第二个矩阵的行列数和非零元素个数";
cin >> m >> n >> num;
TripleMatrix TripleB(m, n, num);
TripleB.inputMatrix(m, n, num);
TripleB.printTriple();
TripleB.printMatrix();
TripleMatrix TripleC;
MatrixMul(TripleA, TripleB, TripleC);
TripleC.printTriple();
TripleC.printMatrix();
}
break;
case 3: //转置矩阵1
TransposeSMatrix(TripleA, TripleB);
cout << "转置后的矩阵为:\n";
TripleB.printTriple();
TripleB.printMatrix();
break;
case 4: //转置矩阵2
FastTransposeSMatrix(TripleA, TripleB);
cout << "转置后的矩阵为:\n";
TripleB.printTriple();
TripleB.printMatrix();
break;
case 5: //转置矩阵3
fastTransposeMatrix(TripleA, TripleB);
cout << "转置后的矩阵为:\n";
TripleB.printTriple();
TripleB.printMatrix();
break;
}
return 0;
}