• 数据结构基础(一)数组,矩阵


    数据结构基础()

    有一个等式,数据结构+算法=程序,说明了数据结构对于计算机程序设计的重要性。数据结构是指数据元素的集合(或数据对象)及元素间的相互关系和构造方法。数据对象中元素之间的相互关系称为数据的逻辑结构,数据元素及元素之间关系的存储形式称为存储结构(或物理结构)。

    数据结构按照逻辑关系的不同,分为线性结构和非线性结构两种,线性结构又可分为树结构和图结构。

     

    1.1 数组

    1.数组的定义和基本运算

     数组是程序中最常用的数据结构,数组的本质是内存中一段大小固定,地址连续的存储单元。

    一维数组是一个长度固定,下标有序的线性序列。二位数组则是一个矩阵结构,本质上是以数组作为数组元素的数组,即“数组的数组”。以二维数组A[m,n]为例,其结构如图2-1所示:

     

    A[m,n]可以看做一个行向量形式的线性序列:

    Am,n =[[a11,a12…a1n],[ a21,a22…a2n],…,[ am1,am2…amn]];

    也可以看做一个列向量形式的线性序列

    Am,n =[[a11,a21…am1],[ a12,a22…am2],…,[ a1n,a2n…amn]];

                           二维数组的本质是一维数组的数组

    数组的结构特点:

    数组元素数目固定,一旦定义不可改变。

    数组中的元素具有相同的类型。

    数组下标具有上下界的约束且有序。

    数组的两个基本运算:

    给定一组下标,存取相应的数据元素。

    给定一组下标,更改相应元素的值。

     在程序设计语言中,把数组看做是具有共同名字的相同类型的多个变量的集合。

    2  数组元素的存储

     

    数组适合采用顺序存储结构,对于数组一旦确定了其维数和各维的长度,便可分配存储空间。所以,只要给出一组下标便可求出相应数组元素的存储位置,在数组的顺序存储结构中,数组元素的位置和其下标呈线性关系。

          二维数组的存储结构可分为以行为主存储和以列为主存储两种方式

     

    设每个数组元素占用L个单元,m,n为数组的行数和列数,Loc(a11)表示元素a11的地址,

            以行为主:

                           Loc(aij)=Loc(a11)+(i-1) ×n+(j-1) ×L

           以列为主:

                            Loc(aij)=Loc(a11)+(j-1) ×m+(i-1) ×L

    推广至多维数组,按下标顺序(以行为主)存储时,先排最右的下标,从右至左到最左下标,而逆下标顺序正好相反。

     

    3.矩阵

    在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合 [1]  ,最早来自于方程组的系数及常数所构成的方阵。这一概念由19世纪英国数学家凯利首先提出。在数据结构中,主要讨论如何在节省存储空间的前提下,正确高效的运算矩阵。

    在实际应用中,经常出现一些阶数很高的矩阵,同时在矩阵中有很多值相同的元素并且它们的分布有一定的规律——称为特殊矩阵(special matrix),对称矩阵就是其中一种。对称矩阵的特点是:在一个n阶方阵中,有aij=aji(1≤i,j≤n)。可以对这类矩阵进行压缩存储,从而节省存储空间,并使矩阵的各种运算能有效进行。

    (1) 对称矩阵

         对称矩阵关于主对角线对称,因此只需存储下三角部分(包括主对角线)即可。这样,原来需要存储n×n个存储单元,现在只需要n×(n+1)/2个存储单元,节约了大约一半的存储单元。当n较大时,这是比较可观的一部分存储单元。

    如何只存储下三角部分的元素呢?由于下三角中共有n×(n+1)/2个元素,可将这些元素按行存储到一个数组SA[n(n+1)/2]中。这样,下三角中的元素aij(i≥j)存储到SA[k]中,在数组SA中的下标k和i、j的关系为:k=i×(i-1)/2+j-1,寻址的计算方法如图所示。

    Java代码实现对称矩阵存储压缩:


     

    package top.yxy.xs;
    
    /**
     * 稀疏矩阵的压缩存储
     * 
     * 稀疏矩阵三元组顺序表
     * 
     * 三元组顺序存储的稀疏矩阵类
     * 
     * @author clarck
     * 
     */
    public class SeqSparseMatrix {
        // 矩阵行数、列数
        private int rows, columns;
    
        // 稀疏矩阵三元组顺序表
        private SeqList<Triple> list;
    
        /**
         * 构造rows行,colums列零矩阵
         * 
         * @param rows
         * @param columns
         */
        public SeqSparseMatrix(int rows, int columns) {
            if (rows <= 0 || columns <= 0)
                throw new IllegalArgumentException("矩阵行数或列数为非正数");
    
            this.rows = rows;
            this.columns = columns;
            // 构造空顺序表,执行SeqList()构造方法
            this.list = new SeqList<Triple>();
        }
    
        public SeqSparseMatrix(int rows, int columns, Triple[] elems) {
            this(rows, columns);
            // 按行主序插入一个元素的三元组
            for (int i = 0; i < elems.length; i++)
                this.set(elems[i]);
        }
    
        /**
         * 返回矩阵第i行第j列元素,排序顺序表的顺序查找算法,O(n)
         * 
         * @param i
         * @param j
         * @return
         */
        public int get(int i, int j) {
            if (i < 0 || i >= rows || j < 0 || j >= columns)
                throw new IndexOutOfBoundsException("矩阵元素的行或列序号越界");
    
            Triple item = new Triple(i, j, 0);
            int k = 0;
            Triple elem = this.list.get(k);
            // 在排序顺序表list中顺序查找item对象
            while (k < ((CharSequence) this.list).length() && item.compareTo(elem) >= 0) {
                // 只比较三元组元素位置,即elem.row == i && elem.column == j
                if (item.compareTo(elem) == 0)
                    return elem.value;
                // 查找到(i, j), 返回矩阵元素
                k++;
                elem = ((Object) this.list).get(k);
            }
            return 0;
        }
    
        /**
         * 以三元组设置矩阵元素
         * 
         * @param elem
         */
        public void set(Triple elem) {
            this.set(elem.row, elem.colum, elem.value);
        }
    
        /**
         * 设置矩阵第row行第column列的元素值为value,按行主序在排序顺序表list中更改或插入一个元素的三元组, O(n)
         * 
         * @param row
         * @param column
         * @param value
         */
        public void set(int row, int column, int value) {
            // 不存储值为0元素
            if (value == 0)
                return;
    
            if (row >= this.rows || column >= this.columns)
                throw new IllegalArgumentException("三元组的行或列序号越界");
    
            Triple elem = new Triple(row, column, value);
            int i = 0;
            // 在排序的三元组顺序表中查找elem对象,或更改或插入
            while (i < this.list.length()) {
                Triple item = this.list.get(i);
                // 若elem存在,则更改改位置矩阵元素
                if (elem.compareTo(item) == 0) {
                    // 设置顺序表第i个元素为elem
                    this.list.set(i, elem);
                    return;
                }
    
                // elem 较大时向后走
                if (elem.compareTo(item) >= 0)
                    i++;
                else
                    break;
            }
            this.list.insert(i, elem);
        }
    
        @Override
        public String toString() {
            String str = "三元组顺序表:" + this.list.toString() + "
    ";
            str += "稀疏矩阵" + this.getClass().getSimpleName() + "(" + rows + " * "
                    + columns + "): 
    ";
            int k = 0;
            // 返回第k个元素,若k指定序号无效则返回null
            Triple elem = this.list.get(k++);
            for (int i = 0; i < this.rows; i++) {
                for (int j = 0; j < this.columns; j++)
                    if (elem != null && i == elem.row && j == elem.colum) {
                        str += String.format("%4d", elem.value);
                        elem = this.list.get(k++);
                    } else {
                        str += String.format("%4d", 0);
                    }
                str += "
    ";
            }
            return str;
        }
    
        /**
         * 返回当前矩阵与smat相加的矩阵, smatc=this+smat,不改变当前矩阵,算法同两个多项式相加
         * 
         * @param smat
         * @return
         */
        public SeqSparseMatrix plus(SeqSparseMatrix smat) {
            if (this.rows != smat.rows || this.columns != smat.columns)
                throw new IllegalArgumentException("两个矩阵阶数不同,不能相加");
    
            // 构造rows*columns零矩阵
            SeqSparseMatrix smatc = new SeqSparseMatrix(this.rows, this.columns);
            int i = 0, j = 0;
            // 分别遍历两个矩阵的顺序表
            while (i < this.list.length() && j < smat.list.length()) {
                Triple elema = this.list.get(i);
                Triple elemb = smat.list.get(j);
    
                // 若两个三元组表示相同位置的矩阵元素,则对应元素值相加
                if (elema.compareTo(elemb) == 0) {
                    // 相加结果不为零,则新建元素
                    if (elema.value + elemb.value != 0)
                        smatc.list.append(new Triple(elema.row, elema.colum,
                                elema.value + elemb.value));
    
                    i++;
                    j++;
                } else if (elema.compareTo(elemb) < 0) { // 将较小三元组复制添加到smatc顺序表最后
                    // 复制elema元素执行Triple拷贝构造方法
                    smatc.list.append(new Triple(elema));
                    i++;
                } else {
                    smatc.list.append(new Triple(elemb));
                    j++;
                }
            }
    
            // 将当前矩阵顺序表的剩余三元组复制添加到smatc顺序表最后
            while (i < this.list.length())
                smatc.list.append(new Triple(this.list.get(i++)));
    
            // 将smat中剩余三元组复制添加到smatc顺序表最后
            while (j < smatc.list.length()) {
                Triple elem = smat.list.get(j++);
                if (elem != null) {
                    smatc.list.append(new Triple(elem));
                }
            }
    
            return smatc;
        }
    
        /**
         * 当前矩阵与smat矩阵相加,this+=smat, 改变当前矩阵,算法同两个多项式相加
         * 
         * @param smat
         */
        public void add(SeqSparseMatrix smat) {
            if (this.rows != smat.rows || this.columns != smat.columns)
                throw new IllegalArgumentException("两个矩阵阶数不同,不能相加");
    
            int i = 0, j = 0;
            // 将mat的各三元组依次插入(或相加)到当前矩阵三元组顺序表中
            while (i < this.list.length() && j < smat.list.length()) {
                Triple elema = this.list.get(i);
                Triple elemb = smat.list.get(j);
    
                // 若两个三元组表示相同位置的矩阵元素,则对应元素值相加
                if (elema.compareTo(elemb) == 0) {
                    // 相加结果不为0,则新建元素
                    if (elema.value + elemb.value != 0)
                        this.list.set(i++, new Triple(elema.row, elema.colum,
                                elema.value + elemb.value));
                    else
                        this.list.remove(i);
                    j++;
                } else if (elema.compareTo(elemb) < 0) { // 继续向后寻找elemb元素的插入元素
                    i++;
                } else {
                    // 复制elemb元素插入作为this.list的第i个元素
                    this.list.insert(i++, new Triple(elemb));
                    j++;
                }
            }
    
            // 将mat中剩余三元组依次复制插入当前矩阵三元组顺序表中
            while (j < smat.list.length()) {
                this.list.append(new Triple(smat.list.get(j++)));
            }
        }
    
        // 深拷贝
        public SeqSparseMatrix(SeqSparseMatrix smat) {
            this(smat.rows, smat.columns);
            // 创建空顺序表,默认容量
            this.list = new SeqList<Triple>();
            // 复制smat中所有三元组对象
            for (int i = 0; i < smat.list.length(); i++)
                this.list.append(new Triple(smat.list.get(i)));
        }
    
        /**
         * 比较两个矩阵是否相等
         */
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
    
            if (!(obj instanceof SeqSparseMatrix))
                return false;
    
            SeqSparseMatrix smat = (SeqSparseMatrix) obj;
            return this.rows == smat.rows && this.columns == smat.columns
                    && this.list.equals(smat.list);
        }
        
        /**
         * 返回转置矩阵
         * @return
         */
        public SeqSparseMatrix transpose() {
            //构造零矩阵,指定行数和列数
            SeqSparseMatrix trans = new SeqSparseMatrix(columns, rows);
            for (int i = 0; i < this.list.length(); i++) {
                //插入矩阵对称位置元素的三元组
                trans.set(this.list.get(i).toSymmetry());
            }
            return trans;
        }
        
    }

    (2)稀疏矩阵

    在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵。稀疏矩阵常使用三元组存储法,三元组表示法就是在存储非零元的同时,存储该元素所对应的行下标和列下标。稀疏矩阵中的每一个非零元素由一个三元组(i,j,aij)唯一确定。矩阵中所有非零元素存放在由三元组组成的数组中。

     

    查看更多文章欢迎关注我的微信公众号:AlbertYang

  • 相关阅读:
    【leetcode】1415. The k-th Lexicographical String of All Happy Strings of Length n
    【leetcode】1413. Minimum Value to Get Positive Step by Step Sum
    【leetcode】1410. HTML Entity Parser
    【leetcode】1409. Queries on a Permutation With Key
    1, 2, and 4 symbols per clock中数据排列
    RGB转换成YCbCr
    RAW转换成RGB
    ROM的一种写法
    IP之ALTIOBUF仿真
    IP之ALTDDIO_in仿真
  • 原文地址:https://www.cnblogs.com/yangxianyang/p/13675677.html
Copyright © 2020-2023  润新知