数据结构| 数组

数组的定义

数组是由n个类型相同的数据元素组成的有限序列。其中,这n个数据元素占用一块地址连续的存储空间。数组中的数据元素可以是原子类型,如整型、字符型、浮点型等,统称为一维数组;也可以是一个线性表,这种类型的数组称为二维数组。

数组的抽象类型定义如下:

ADT Array{
    数据对象;
    数据关系;

    基本操作:
        InitArray(Array &A,int dim,...)
            操作结果:若维数dim和随后的各维长度合法,则构造相应的数组A
        DestroyArray(Array &A)
            初始条件:存在数组
            操作结果:销毁数组A
        Value(Array A,ElemType &e,...)
            初始条件:存在数组
            操作结果:A是n维数组,e为元素变量,随后是n个下标值;若下表不超界,则将e赋值为所指定的A的元素
        Assign(Array &A,ElemType e,...)
            初始条件:存在数组
            操作结果:A是n维数组,e为元素变量,随后是n个下标值;若下表不超界,则将e赋值给所指定的A的元素
}

数组的顺序表示与实现

1.宏定义解释

#include<stdarg.h>   标准头文件,提供va_start、va_arg等
#define MAX_ARRAY_DIM 8  //假设数维数最大值为8

2.结构类型

typedef struct{
    ElemType *base;  //数组元素的基址
    int dim;  //数组维数
    int *bounds;  //数组维届基址
    int *constants;  //数组映像函数常量基址
}Array;

特殊矩阵的压缩存储

在矩阵的运算中往往会出现阶数很高的矩阵中存在许多相同的元素或者值为0的元素。为了节省空间需要将这些矩阵进行压缩存储。

1.对称矩阵的压缩存储

如果一个n阶矩阵A中的元素满足性质aij = aji,则称这样的矩阵为n阶对称矩阵。由于对称矩阵中的元素关于主对角线对称,因此在对矩阵存储时,可以只存储对称矩阵中的上三角或者下三角元素,使得对称的元素共享一个存储单元,这样就可以实现压缩的目的。

假设一维数组s存储对称矩阵A的上三角或者下三角元素,则一维数组s的下标k与n阶对称矩阵A的元素aij之间的对称关系为:


对称矩阵

其中当i>=j时表示的是下三角的情况,而i<j时表示的是上三角的情况。

2.三角矩阵的压缩存储

三角矩阵分为两种:上三角矩阵和下三角矩阵。其中,下三角元素均为常数或0的n阶矩阵称为上三角矩阵,反之则称为下三角矩阵。在三角矩阵中,重复元素可以用一个存储单元来进行存储,而其他的元素可以用对称矩阵的压缩存储方式来存储。

如果用一维数组来存储三角矩阵,则需要存储n* (n+1)/2+1个元素。一维数组的下标k与矩阵的下标(i,j)的对应关系为:


其中n*(n+1)/2这个位置是用来存放常数或者0元素的。

3.对角矩阵的压缩存储

对角矩阵就是所有的非0元素都集中在主对角线两侧的带状区域内(对角线的个数为奇数)。也就是说除了主对角线和其两边的对角线外,其他元素的值均为0。


对角矩阵

对角矩阵具有如下特点:

  • 第一行和最后一行有2个非零元素,第2-n-1行有3个非零元素。
  • 前i-1行有3*(i-1)-1个非零元素,第i行的非零元素个数为j-i+1当j<i时,j-i = -1当j>i时j-i=1。
  • 使用一维数组存储,需要存储3*n-2个元素。
  • 一维数组s[k]和A[i][j]的对应关系为:k = 2*i+j。

4.稀疏矩阵的压缩存储

稀疏矩阵是指在m x n矩阵中,有t个元素不为0,且t/(m+n)<=0.05,我们把这样的矩阵叫做稀疏矩阵。也就是说矩阵中存在大多数为0的元素,只有很少的非0元素,这样的矩阵就是稀疏矩阵。由于稀疏矩阵中的非0元素很少,因此稀疏矩阵也需要进行压缩存储。

稀疏矩阵的抽象类型定义如下:

ADT SparseMatrix{
    数据对象;
    数据关系;

    基本操作:
        CreateMatrix(&M)
            操作结果:创建稀疏矩阵
        DestroyMatrix(&M)
            初始条件:存在稀疏矩阵
            操作结果:销毁稀疏矩阵M
        PrintSMatrix(M)
            初始条件;存在稀疏矩阵
            操作结果:输出稀疏矩阵M
        CopyMatrix(M,&N)
            初始条件:存在稀疏矩阵
            操作结果:由稀疏矩阵M复制得到T
        TransposeSMatrix(M,&N)
            初始条件:存在稀疏矩阵
            操作结果:求稀疏矩阵M的转置矩阵T
}
稀疏矩阵的表示与实现

为了实现压缩存储,可以只存储稀疏矩阵中的非0元素。在存储稀疏矩阵中的非0元素时,还必须存储非0元素对应的行和列的位置(i,j)。也就是说,存储一个非0元素需要存储元素的行号列号和元素的值。在这里我们可以采用三元组的方式来进行存储。

1.宏定义解释

#define MaxSize 200  //三元组的个数
#typedef DataType int;  //定义为int类型

2.结构类型

typedef struct{
    int i;  //行号
    int j;  //列号
    DataType e;  //值
}Triple;
//定义矩阵
typedef struct{
    Triple data[Maxsize];  
    int m;  //矩阵的行数
    int n;  //矩阵的列数
    int len;  //非0元素的个数
}TriSeqMatrix;

3.基本操作的实现
(1)创建稀疏矩阵CreatMatrix

int CreatMatrix(TriSeqMatrix *M){
    int i,m,n;
    DataType e;
    int flag;  //设置标志位
    cout<<"Enter the number of rows, columns, and non-zero elements:"<<endl;  //输入行数、列数和非0元素的个数
    cin>>M->m;
    cin>>M->n;
    cin>>M->len;
    if(M->len>Maxsize){  //如果超过最大容量则返回0
        return 0;
    }
    for(i=0;i<M->len;i++){  //开始输入
        do{
            cout<<"Enter the number of rows,columns and values for the NO."<<i+1<<"number"<<endl;  //输入每一个非0元素的行数列数与数值
            cin>>m;
            cin>>n;
            cin>>e;
            flag=0;  //初始化标志位
            if(m<0||m>M->m||n<0||n>M->n){  //如果输入错误,则标志位为0
                flag=0;  
            }
            if(i>0&&m<M->data[i-1].i||m==M->data[i-1].i&&n<=M->data[i-1].j){
                flag=1;
            }
        }while(flag)
        M->data[i].i=m;
        M->data[i].j=n;
        M->data[i].e=e;
    }
    return 1;
}

(2)销毁稀疏矩阵DestroyMatrix

void DestroyMatrix(TriSeqMatrix *M){
    M->m=M->n=M->len=0;  //全部置为零
}

(3)矩阵的复制CopyMatrix

void CopyMatrix(TriSeqMatrix M,TriSeqMatrix *N){
//稀疏矩阵M复制得到另一个矩阵N
    int i;
    N->len = M.len;
    N->m = M.m;
    N->n = M.n;
    for(i=0;i<M.len;i++){
        N->data[i].i=M.data[i].i;
        N->data[i].j=M.data[i].j;
        N->data[i].e=M.data[i].e;
    }
}

(4)矩阵的转置TransposeMatrix

void TransposeMatrix(TriSeqMatrix M,TriSeqMatrix *N){
    int i,k,col;
    N->m=M.n;
    N->n=M.m;
    N->len=M.len;
    if(N->len){
        k=0;
        for(col=0;col<M.n;col++){  //按照列号开始扫描三元组
            for(i=0;i<M.len;i++){
                if(M.data[i].j==col){  //如果列号是当前的列,则进行转置
                    N->data[k].i=M.data[i].j;
                    N->data[k].j=M.data[i].i;
                    N->data[k].e=M.data[i].e;
                    k++;
                }
            }
        }
    }
}
稀疏矩阵的十字链表表示与实现

稀疏矩阵的十字链表表示就是采用链式存储的方式来进行的,链表中的每个结点存储稀疏矩阵中的每个非0元素。每个结点包含5个域:3个数据域和2个指针域。其中3个数据域分别表示非0元素的行号、列号以及元素值;2个指针域是right域和down域,right指向同一行中的下一个非0元素,down指向同一列的非0元素。

1.宏定义解释

#typedef int DataType;  //定义为int类型

2.结构类型

typedef struct OLNode{  //定义结点
    int i,j;  //非0元素行号与列号
    DataType e;  //非0元素值
    struct OLNode *right,*down;  //同一行与同一列下一个非0元素
}OLNode,*OLink;
typedef struct{  //定义链表
    OLink *rowhead,*colhead;  //指向行链表与列链表的指针
    int m,n,len;  //稀疏矩阵的行数、列数与非0元素的个数
}CrossList;

3.具体操作的实现
(1)初始化稀疏矩阵InitMatrix

void InitMatrix(CrossList *M){
    M->rowhead=M->colhead=NULL;
    M->m=M->n=M->len=0;
}

**(2)创建稀疏矩阵CreatMatrix

void CreateMatrix(CrossList *M){
    int i,k;
    int m,n,num;
    OLNode *p,*q;
    cout<<"enter the number of rows, columns, and non-zero elements:"<<endl;
    cin>>m;
    cin>>n;
    cin>>num;
    M->m=m;
    M->n=n;
    M->len=num;
    M->rowhead=(OLink*)malloc(m*sizeof(OLink));
    if(!M->rowhead){
        exit(-1);
    }
    for(k=0;k<m;k++){
        M->rowhead[k]=NULL;
    }
    for(k=0;k<n;k++){
        M->colhead[k]=NULL;
    }
    printf("按照次序输入%d个非0元素的行号、列号以及元素值:",M->len);
    for(k=0;k<num;k++){
        p=(OLNode*)malloc(sizeof(OLNode));
        if(!p){
            exit(-1);
        }
        scanf("%d %d %d",&p->i,&p->j,&p->e);
        if(M->rowhead[p->i]==NULL||M->rowhead[p->i]->j>p->j){
            p->right=M->rowhead[p->i];
            M->rowhead[p->i]=p;
        }
        else{
            q=M->rowhead[p->i];
            while(q->right&&q->right->j<p->j)
            q=q->right;
            p->right=q->right;
            q->right=p;
        }
        q=M->colhead[p->j];
        if(!q||p->i<q->i){
            p->down=M->colhead[p->j];
            M->colhead[p->j]=p;
        }
        else{
            while(q->down&&q->down->i<p->i)
            q=q->down;
            p->down=q->down;
            q->down=p;
        }
    }
}

**(3)稀疏矩阵的插入InsertMatrix

void InsertMatrix(CrossList *M,OLink p){
//按照行序将p插入到稀疏矩阵中
    OLink q=M->rowhead[p->i];
    if(!q||p->j<q->j){
        p->right=M->rowhead[p->i];
        M->rowhead[p->i]=p;
    }
    else{
        while(q->right&&q->right->j<p->j){
            q=q->right;
        }
             p->right=q->right;
             q->right=p;
    }
    q=M->colhead[p->i];
    if(!q||p->i<q->i){
        p->down=M->colhead[p->j];
        M->colhead[p->j]=p;
    }
    else{
        while(q->down&&q->down->i<p->i){
            q=q->down;
        }
        p->down=q->down;
        q->down=p;
    }
    M->len++;
}

**(4)稀疏矩阵的销毁DestroyMatrix

void DestroyMatrix(CrossList *M){
    int i;
    OLink p,q;
    for(i=0;i<M->m;i++){  //开始按照行释放结点
        p=*(M->rowhead+i);
        while(p){
            q=p;
            p=p->right;
            free(q);
        }
    }
    free(M->rowhead);  //释放行链表
    free(M->colhead);  //释放列链表
    InitMatrix(M);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容