数组与矩阵

来源:互联网 发布:淘宝运营工资怎么样 编辑:程序博客网 时间:2024/06/07 04:12

[toc]
数组是我们比较常接触的一种数据结构了,就我们所了解的,数组从一维到多维不等,由数组演变出来的另一概念,被称之为矩阵,但是其实质还是一种有序的序列。

1. 数组


数组的存储和寻址

数组可以是一维的,也可以是多维的,多维数组可以实现向一维数组的转换,根据不同的优先顺序,可以有不同的转换方案,但是为了方便,我们对数组的存储和寻址进行了相关的约定:

  • 数组是以线性方式进行存储的。设有一个一维数组A[n],其中每个数组元素的存储空间为C个字节,则数组第i个元素的首地址为A[0] + i x C,即Loc(A[i]) = Loc(A[0]) + i x C 其中Loc表示元素首地址。

  • 多维数组按照行优先原则进行存储。即设有一个二维数组A[m][n],其中每个数组元素占空间为C个字节,则数组元素A[i][j]的存储首地址为A[0][0] + i x n x C + j x C,即Loc(A[i][j]) = Loc(A[0][0] + (i x j x n) x C

    一般所使用的C,C++,Java等语言均是按行优先原则,而MATLAB等语言则是按列优先存储。

接下来给出一维数组的实现。

class Array{    private:        int size;  //数组大小        int *list;  //指向数组第一个元素    public:        Array(int size = 0);        Array(const Array &v);   //用于数组的复制        ~Array() { delete[] list; }        int ArraySize() { return size; }        int & operator[] (int i)const;  //重载下标符        Array & operator= (const Array &v)const;  //重载复制运算符        Array & operator+ ()const;   //重载一元加法        Array & operator+ (const Array &v)const;    //重载二元加法        Array & operator- ()const;   //重载一元减法        Array & operator- (const Array &v)const;   //重载二元减法};

其中,数组的运算可以通过函数来实现,并不一定需要通过重载运算符来实现,这也说明,在编程时,方法不是主要的,只要知道最核心的思想,实现方法怎么顺手怎么来。

2. 矩阵


矩阵其实是一种比较特殊的二维数组,不过由于其特殊性,我们会单独为他做一些实现来简化工作。
矩阵在线性代数中会有专门的讲解,有很多的运算,很多的定义。矩阵的知识学着学着,就会让人怀疑人生,好在,不研究这东西,只需要会用就行。
普通矩阵的一种实现:

class Matrix{    private:        int rows, cols;    //矩阵行和列        int *element;    //矩阵中的元素    public:        Matrix(int r, int c);        Matrix(const Matrix &m);    //用于复制的构造函数        ~Matrix() { delete[] element; }        int Rows()const { return rows; }        int Columns()const { return cols; }        int & operator() (int i, int j)const;    //重载下标操作符        Matrix &operator+ ()const;        Matrix &operator+ (const Matrix &m)const;        Matrix &operator- ()const;        Matrix &operator- (const Matrix &m)const;        Matrix &operator* (const Matrix &m)const;};

2.1 特殊矩阵

如果采用矩阵存储数据时,可能会出现部分位置空闲,元素重复等情况,会造成大量的空间浪费,如此一来便出现了一些特殊矩阵:

  1. 对角矩阵
    在数学中规定,一个n x n维方阵,其非对角线上的元素均为0,就称这种矩阵为对角矩阵
    通过定义,我们便可发现,一个n x n维对角矩阵,至多有n个非零元素,也即只需存储n个对角元素的信息。
    这种情况,我们可以通过一维数组进行存储,通过相应的运算,决定对角元素所在位置。

    但这相应的运算其实可以是A[i]存储矩阵A[i][i]的元素。

  2. 三角矩阵
    三角矩阵又可细分为上三角矩阵下三角矩阵
    在数学中规定,一个n x n维方阵,其中对于任意i

2.2 三元组表

稀疏矩阵不能使用普通的矩阵进行存储,于是我们想到可以直接存储稀疏矩阵中的有效信息,进而诞生了三元组表
三元组表是由结点构成,每一个结点又是由一个结构体构成,该结构体有row,col,value三个域,存储元素的行列值信息。
三元组表

上图为三元组表的内容。

三元组表的实现为:

struct Trituple{    int row, col;    int value;};class SparseMatrix{    private:        int rows, cols, count;   //稀疏矩阵的行列数,以及非零元素的个数        Trituple *smArray;    //存储三元组表的数组        int MaxTerm;  //数组的大小    public:        SparseMatrix(int Mrows, int Mcols);        SparseMatrix Transpose();   //求转置矩阵        /* 与普通矩阵的其他操作相同 */};

2.3 十字链表

稀疏矩阵的另一种实现是十字链表,这种十字链表是由结点构成,结点中的内容为,左邻非零元素指针,上邻非零元素的指针,以及行列值的信息。
十字链表的结点

听起来这种存储方式要比三元组表麻烦,实际上也确实如此,不过这种存储方式奉行的是牺牲空间换时间原则,因此查找起来速度还是很快的。

这里说说三元组表的缺点,三元组表无论是添加或是删除矩阵中的非零元素,又或是说对矩阵实施一些操作(如运算),都会引起矩阵中非零元素的个数和位置变化,这种变化会使三元组表大量的结点进行移动,效率较低,使用链接存储则避免了这些问题。

原创粉丝点击