数据结构(C语言版 严蔚敏著)——数组和广义表

这一章只要理解,不作深入要求

数组顺序存储结构以及一些操作

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#define MAX_ARRAY_DIM 8
typedef int ElemType;
typedef struct {
    ElemType *base; //数组元素基址
    int dim;        //维数
    int *bounds;    //数组维界基址
    int *constants; //数组映像函数常量基址
} Array;

int InitArray(Array &A, int dim, ...) {
    //这里用的是“可变参”形参方式。它主要解决维数不定的问题。
    //举例:设有4维数组,各维分别是:4,5,6,7(这些数字是随意给的),那么,调用方式:
    //InitArray(ar, 4, 4, 5, 6, 7);
    //ar其中,ar也是假设的变量名称, 4表示数组有4维, 4, 5, 6, 7这4个数是各维大小
    //如果是5维的,那么就这样:
    //InitArray(ar, 5, 第一维数,第二维数,第三维数,第四维数,第五维数);
    //若维数dim和随后的各维长度合法,则构造相应的数组A,并返回OK。
    if (dim < 1 || dim > MAX_ARRAY_DIM)
        return 0;
    A.dim = dim;
    A.bounds = (int *) malloc(dim * sizeof(int));
    if (!A.bounds)
        exit(0);
    //若各维长度合法,则存入A.bounds,并求出A的元素总数elemtotal。
    int elemtotal = 1;
    //ap为va_list类型,是存放变长参数表信息的数组。
    va_list ap;
    //dim表示最后一个确定的参数,把后面的参数都存在ap中
    //va_start
    va_start(ap, dim);
    for (int i = 0; i < dim; ++i) {
        //每当取出一个参数,ap指针就指向下一个
        A.bounds[i] = va_arg(ap, int);
        //变参不合法,返回0
        if (A.bounds[i] < 0)
            return 0;
        //把各维度相乘,即为元素总量
        elemtotal *= A.bounds[i];
    }
    //va_end
    va_end(ap);
    //分配元素空间
    A.base = (ElemType *) malloc(elemtotal * sizeof(ElemType));
    if (!A.base)
        exit(0);
    //求映像函数的常数ci,并存入A.constants[i-1],i=1,...,dim
    A.constants = (int *) malloc(dim * sizeof(int));
    if (!A.constants)
        exit(0);
    //第一维映像函数为1
    A.constants[dim - 1] = 1;
    //从二维开始,映像函数=上一维的大小*上一维映像函数的大小
    //下面有对constants的详细解释 
    for (int i = dim - 2; i >= 0; --i) {
        A.constants[i] = A.bounds[i + 1] * A.constants[i + 1];
    }
    return 1;
}

int DeatroyArray(Array &A) {
    //销毁数组A。
    if (!A.base)
        return 0;
    free(A.base);
    A.base = NULL;
    if (!A.bounds)
        return 0;
    free(A.bounds);
    A.bounds = NULL;
    if (!A.constants)
        return 0;
    free(A.constants);
    A.constants = NULL;
    return 1;
}

// 在定位一个数组元素的时候,比如要求a[2][2][4]元素的值,按照我们的常理,可以直接用
// a[2][2][4] = x;来赋值或者取值,但是这里定义的数组维度是可以改变的,比如说8维,
// 而且数组的空间都是用malloc函数分配得到的,基址为结构体里面的指针。
// 这时就不能再用上面的方法求值或者复制。需要得到我们要赋值或者取值的元的地址,
// 通过地址操作来进行值的获取。
// 因为是a[3][4][5],所以a[2][2][4]的地址就是base+2*4*5+2*5+4*1;为了简便,
// 在结构体中设置了constants
int Locate(Array A, va_list ap, int &off) {
    //若ap指示的各下标值合法,则求出该元素在A中相对地址off
    //ap指数组一系列下标,比如a[2][2][4],那么这个 va_list为(2,2,4)
    off = 0;
    int ind;
    for (int i = 0; i < A.dim; ++i) {
        ind = va_arg(ap, int);
        //ind合法大小为0~A.bounds[i]-1
        if (ind < 0 || ind >= A.bounds[i])
            return 0;
        off += A.constants[i] * ind;
    }
    return 1;
}

int Value(Array A, ElemType &e, ...) {
    //A是n维数组,e为元素变量,随后是n个下标值
    //若各下标不超界,则e赋值为所指定的A的元素值,返回1
    va_list ap;
    int off, result;
    //va_list从确定参数e后面开始
    va_start(ap, e);
    result = Locate(A, ap, off);
    if (result <= 0)
        return result;
    //基地址+相对地址=元素真正地址
    e = *(A.base + off);
    return 1;
}

int Assign(Array &A, ElemType e, ...) {
    //A是n维数组,e为元素变量,随后是n个下标值
    //若下标不超界,则将e的值赋给所指定的A的元素,并返回1
    va_list ap;
    va_start(ap, e);
    int result, off;
    result = Locate(A, ap, off);
    if (result <= 0)
        return 0;
    *(A.base + off) = e;
    return 1;
}

三元组顺序表

#define MAXSIZE 12500   //假设非零元个数的最大值为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;

int TransposeSMatrix(TSMatrix M, TSMatrix &T) {
    //采用三元组存储表示,求稀疏矩阵M的转置矩阵T
    //时间复杂度O(nu*tu)
    //此算法仅适于tu<<mu*nu的情况
    T.mu = M.nu;//行数为 M的列数
    T.nu = M.mu;//列数为 M的行数
    T.tu = M.tu;//非零元素个数
    if (T.tu) {
        int q = 1;
        //列循环
        for (int col = 1; col <= M.nu; ++col)
            //在非零元素中找列下标相等的,互换
            for (int p = 1; p <= M.tu; ++p)
                if (M.data[p].j == 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;
                    ++q;
                }
    }
    return 1;
}

int FastTransposeSMatrix(TSMatrix M,TSMatrix &T){
    //采用三元组顺序表存储表示,求稀疏矩阵M的转置矩阵T
    //此方法称为快速转置
    //多用了两个辅助向量,算法中有4个单循环,分别为nu,tu
    //总时间复杂度为O(nu+tu)
    //在M的非零个数tu和mu*nu等数量级时
    //时间复杂度为O(mu*nu),这时和上面的时间复杂度相同
    T.mu=M.nu;
    T.nu=M.mu;
    T.tu=M.tu;
    int col,q;
    int num[T.nu+1];
    int cpot[T.nu+1];
    cpot[1]=1;
    if(T.tu){
        for(col=1;col<=M.nu;++col)
            num[col]=0;//初始化列元素数组
        for(int t=1;t<=M.tu;++t)
            ++num[M.data[t].j];//求M中每一列含非零元素个数
        //求第col列中第一个非零元素在b.data中的序号
        //第一列的起始序号为1
        //第二列的起始序号为第一列非零元素个数加第一列起始序号
        for(col=2;col<=M.nu;++col)
            cpot[col]=cpot[col-1]+num[col-1];
        for (int p = 1; p <= M.tu; ++p) {
            col=M.data[p].j;
            q=cpot[col];
            T.data[q].i=M.data[p].j;
            T.data[q].j=M.data[p].i;
            T.data[q].e=M.data[p].e;
            //当前列第一个元素取出
            ++cpot[col];
        }
    }
    return 1;
}

 

行逻辑链接的顺序表

 

#define MAXSIZE 100
#define MAXRC 100
typedef int ElemType;
typedef struct {
    int i, j;    //该非零元的行下标和列下标
    ElemType e;
} Triple;
typedef struct {
    Triple data[MAXSIZE + 1];//非零元三元组表
    int rpos[MAXRC + 1];  //各行第一个非零元的位置表
    int mu, nu, tu;       //矩阵的行数、列数和非零元个数
} RLSMatrix;

int MultSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix &Q) {
    //求矩阵乘积Q=M*N,采用行逻辑链接存储表示
    //求Q的所有非零元的时间复杂度为O(M.tu*N.tu/N.mu)
    //进行压缩存储的时间复杂度为O(M.mu*N.nu)
    //总的时间复杂度为O(M.mu*N.nu+M.tu*N.tu/N.mu)
    //矩阵乘法规则可知C(i,j) = A(i,1)*B(1,j)+A(i,2)*B(2,j)+....+A(i,n)*B(n,j),
    // 即C(i,j)为A的第i行与B的第j列非零元素乘积之和。设置累加器temp[B的列值]保存
    // C矩阵每行的值,结束后将temp中的值赋给C矩阵。
    if (M.nu != N.mu)
        return 0;
    //Q初始化
    Q.mu = M.mu;
    Q.nu = N.nu;
    Q.tu = 0;
    int ctemp[N.nu + 1];
    int tp, q, p, t, brow, ccol;
    //Q是非零矩阵
    if (M.tu * N.tu != 0) {
        //处理M的每一行
        for (int arow = 1; arow <= M.mu; ++arow) {
            //当前行各元素累加器清零
            ctemp[arow] = 0;
            Q.rpos[arow] = Q.tu + 1;
            if (arow < M.mu)
                tp = M.rpos[arow + 1];
            else
                tp = M.tu + 1;
            for (p = M.rpos[arow]; p < tp; ++p) {
                //对当前行中每个非零元
                //找到对应元在N中的行号
                brow = M.data[p].j;
                if (brow < N.mu)
                    t = N.rpos[brow + 1];
                else
                    t = N.tu + 1;
                for (q = N.rpos[brow]; q < t; ++q) {
                    ccol = N.data[q].j;//乘积元素在Q中列号
                    ctemp[ccol] += M.data[p].e * N.data[q].e;
                }
            }//求得Q中第arow行的非零元
            for (ccol = 1; ccol <= Q.nu; ++ccol) {
                //压缩存储该行非零元
                if (ctemp[ccol]) {//非零元
                    if (++Q.tu > MAXSIZE)
                        return 0;
                    Q.data[Q.tu].i = arow;
                    Q.data[Q.tu].j = ccol;
                    Q.data[Q.tu].e = ctemp[ccol];
                }
            }
        }
    }
    return 1;
}

 

十字链表存储结构和创建

 

typedef int ElemType;
typedef struct OLNode {
    int i, j;
    ElemType e;
    struct OLNode *right, *down;
} OLNode, *OLink;

typedef struct {
    OLink *rhead, *chead;
    int mu, nu, tu;
} CrossList;

int CreateSMatrix_OL(CrossList &M) {
    //创建稀疏矩阵M,采用十字链表存储表示
    int m, n, t, i, j, e;
    OLink p, q;
    scanf("%d%d%d", &m, &n, &t);//输入行数,列数,非零元个数
    M.mu = m;
    M.nu = n;
    M.tu = t;
    if (!(M.rhead = (OLink *) malloc((m + 1) * sizeof(OLink))))
        exit(0);
    if (!(M.chead = (OLink *) malloc((n + 1) * sizeof(OLink))))
        exit(0);
    M.rhead[m + 1] = M.chead[n + 1] = NULL;//初始化行列头指针;各行列链表为空表
    for (scanf("%d%d%d", &i, &j, &e); i != 0; scanf("%d%d%d", &i, &j, &e)) {//按任意次序输入非零元
        if (!(p = (OLink) malloc(sizeof(OLNode))))
            exit(0);
        //生成结点
        p->i = i;
        p->j = j;
        p->e = e;
        if (M.rhead[i] == NULL || M.rhead[i]->j > j) {
            p->right = M.rhead[i];
            M.rhead[i] = p;
        } else {//寻找在行表中插入位置
            for (q = M.rhead[i]; (q->right) && q->right->j < j; q = q->right);
            p->right = q->right;
            q->right = p;//完成行插入
        }
        if (M.chead[j] == NULL || M.chead[j]->i > i) {
            p->down = M.chead[j];
            M.chead[j] = p;
        } else {//寻找在列表中插入位置
            for (q = M.chead[j]; (q->down) && q->down->i < i; q = q->down);
            p->down = q->down;
            q->down = p;//完成列插入
        }
    }
    return 1;
}

 

这一章节需要理解,知道其算法核心思想。

 

 

 

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构c语言)——严蔚敏电子》是一本经典的计算机教材,主要介绍了数据结构和算法的基本概念、原理与实现过程。本书使用C语言进行编,将数据结构C语言相结合,使读者能够更好地理解和应用所学知识。 这本教材的特点有以下几点。首先,它系统地介绍了数据结构和算法的基本概念,包括线性表、栈、队列、树、图等数据结构的定义、操作和应用。其次,书中使用了丰富的实例和案例,帮助读者理解和掌握各种数据结构的应用场景和解决方法。同时,书中还介绍了常用的算法设计和分析方法,如递归、排序、查找等,帮助读者提升自己的编程能力。 此外,这本书的电子具有很多优点。首先,电子可以随时随地进行阅读,方便学习者随身携带和使用。其次,电子还具有搜索功能,可以快速定位所需内容,提高效率。此外,电子还可以进行文字标注和笔记,方便读者加深对知识的理解和记忆。 总的来说,《数据结构c语言)——严蔚敏电子》是一本权威、经典的数据结构教材。它不仅全面系统地介绍了数据结构和算法的基本概念,还适合使用C语言进行实践和应用。同时,电子的优点也使得读者更方便地学习和使用这本书。如果对数据结构和算法感兴趣的人,这本书是一本必读的经典之作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值