为您推荐:
精华内容
最热下载
问答
  • 5星
    3KB weixin_42696333 2021-09-10 20:08:46
  • 目录:containers.Map,tables,enumeration和time series...containers.Map简介MATLAB中最具代表性的高级数据类型是containers.Map,我们可以把它叫做映射表。它和函数映射有些类似,比如函数映射的定义是:F(x) =...

    目录:

    containers.Map,tables,enumeration和time series等等,它们为什么有用,用来解决什么问题,并且怎样在科学工程计算使用。本篇首先介绍 containers.Map 数据类型。

    containers.Map简介

    MATLAB中最具代表性的高级数据类型是containers.Map,我们可以把它叫做映射表。它和函数映射有些类似,比如函数映射的定义是:

    F(x) = Y

    针对每一个X,都有一个唯一的Y与之对应,反之不一定。如图Fig.1所示。和函数映射相似,映射表用来形容键(Key)和键值(Key Value)之间的一一对应关系。每个Key都是独一无二的,且只能对一个Key Value。如图Fig.2所示。

    Fig.1 函数映射关系

    Fig.2 containers.Map类的映射示意图

    数组,元胞和结构体的局限性

    开始我们先介绍一下数组,元胞数组和结构体的局限性,为什么有的时候这些基本的数据类型无法满足程序的要求,换句话说,我们为什么需要 containers.Map 数据结构。假设要用MATLAB来记录电话号码簿中数据,比如表Table.1所示:

    Table.1 电话号码簿姓名

    电话号码

    Abby

    5086470001

    Bob

    5086470002

    Charlie

    5086470003

    先讨论数组,因为电话号码簿中既含有数字,又含有字符串,而数组中只能存放Double类型的数据,所以没有办法用数组直接记录电话号码薄中的内容。

    再试试元胞数组,我们在第1行预先声明一个 3 X 3的元胞数组,然后在2-4行按顺序填放号码簿的内容。

    % 元胞数组初始化

    addressBook = cell(3,1); % 预分配大小是MATLAB编程的好习惯

    addressBook{1} = {'Abby', '5086470001'};

    addressBook{2} = {'Bob' , '5086470002'};

    addressBook{3} = {'Charlie', '5086470003'};

    需要的时候,可以通过for循环访问其中的内容,比如:

    for iter = 1:length(addressBook) % 元胞数组的遍历

    addressBook{iter}          % 通过Index访问元胞中的内容

    end

    但是按照顺序遍历电话号码簿没有什么实际用处,号码簿的主要功能应该是提供查找的功能才是。比如要想查询Charlie的电话号码,我们希望程序最好可以写成如下这样:

    CharlieNum = addressBook{'Charlie'} % 提示:这是错误的写法

    或者

    CharlieNum = addressBook.Charlie % 提示:这是错误的写法

    但是元胞数组的值只能通过Index去访问内容,不支持如上的访问方式。所以为了找到Charlie的电话号码,程序不得不遍历元胞中的所有内容,取出每一个元胞元素的第一列的字符串做比较,如果名字等于Charlie,则输出电话号码:

    % 使用for循环查找

    for iter = 1:length(addressBook)

    if strcmp(addressBook{iter}{1},'Charlie')

    addressBook{iter}{2} % 如找到则输出电话号码

    break;

    end

    end

    当然还有其他的方式来盛放电话号码簿,比如把电话和名字分别存到到两个元胞数组中去

    names = {'Abby','Bob','Charlie'}; % 用元胞放号码

    numbers = {'5086470001','5086470002','5086470001'}; % 用元胞放名字

    ind = find(strcmp(names,'Charlie')); % strcmp接受向量的输入 返回Logical数组

    % find紧接着找出逻辑数组中非零元素的Index

    numbers{ind}

    其中第3行strcmp接受元胞作为输入,在其中寻找Charlie,find函数将返回Charlie所在的位置,这样的方式比使用for循环要快,但无一例外的是,两种方法都要从头开始遍历一个数组,终究来说是慢的。

    除查找性能慢外,使用元胞盛放电话号码簿类型的数据还有其它缺点:

    无法方便的验证重复数据。电话号码簿要求每一个人的名字都是独一无二的,所以在数据录入的时候要防止姓名的重复,但是我们没有其它办法知道某名字是否已经被使用过了,除非在每次输入的时候都对整个元胞里的内容做遍历比较。

    无法方便地添加内容。如果电话号码簿中的记录需要不断地增长,但是我们没有办法在一开始就估计出其大概的数量,于是无法有效的预先分配内存,所以添加数据时,一旦超过预先分配的量,MATLAB就要重新分配内存了。

    无法方便地删除内容。如果我们要从元胞中去掉某一记录,可以找到该记录,并把该位置的元胞内容置空,但这并不会自动减小元胞数组的长度,如果

    这样的删减操作多了,元胞中会留下很多没有利用的空余位置。

    不方便作为函数的参数,具体原因见struct的局限性.

    最后我们再尝试一下用结构体盛放电话号码簿数据类型,struct的赋值很简单,比如可以直接赋值:

    % 赋值方法1

    addressBook.Abby = '5086470001';

    addressBook.Bob = '5086470002';

    addressBook.Charlie = '5086470003';

    或者:

    % 赋值方法2

    addressBook = struct('Abby','5086470001','Bob','5086470002','Charlie','5086470003')

    方法1和方法2是等价的。

    struct数据类型的查找很方便,比如要查询Charlie的电话号码,直接访问struct中的同名的field即可以了。

    num = addressBook.Charlie

    如果要查询的人名是一个变量, 我们可以使用getfield函数:

    num = getfield(addressBook,name) % 其中name是变量

    struct盛放电话号码簿类型的数据,查询起来确实比元胞进步了不少,但还是有些不方便的地方。

    因为struct的field的名字要求必须是以字母开头,这是一个很大的局限,并不是所有的类似电话号码簿的结构都可以用人名做索引,比如账户号码簿,股票代码等等,他们通常是用数字开头的,比如图Table.2中的数据:

    Table.2 深证股票代码股票代码

    股票名称

    000001

    深发展

    000002

    万科

    000004

    ST国农

    如果我们要求通过股票的代码来查找股票的具体信息,struct无法简单的直接做到。

    使用struct的另一个不方便之处在于,当把struct当做函数参数,并且在函数内部需要对该struct做一定的修改时,为了要把修改后的结果返回,我们需要对原来的struct做完全的拷贝,显然如果struct中的数据很多的话,这样做是低效的。比如下面的函数中,addressBook被当做函数的参数传入,在函数中添加了一个新的field, 为了返回更新后的结构,函数内部必须重新构造一个新的struct,也就是s返回给该函数的调用者。

    % 把struct当做函数的参数

    function s = modifystruct(s)

    s.Dave = '5086470004';

    end

    用containers.Map来记录电话号码簿

    上面一节我们介绍了数组,元胞数组和结构体在模拟电话号码簿这种数据结构时的局限性,这节我们来看怎么用 containers.Map 来盛放电话号码簿中的内容:

    addressMap = containers.Map; % 首先声明一个映射表对象变量

    addressMap('Abby') = '5086470001';

    addressMap('Bob') = '5086470002';

    addressMap('Charlie') = '5086470003';

    第一行我们声明一个containers.Map的变量(其实是containers.Map类的对象)叫做addressMap,2,3,4行通过提供Key Key Value的方式来给对象赋值,其中单引号内部的值叫做键(Key),等式右边的叫做键值(Key Value)。通过这个结构,我们在MATLAB内存中,建立起了如图Fig.3的映射关系数据结构。

    Fig.3 电话号码簿映射表

    Fig.4 Map类的UML

    查找addressMap对象中的内容极其方便,比如查找我们想知道Charlie的电话号码,只需:

    % 查找

    num = addressMap('Charlie')

    如果我们要修改Charlie的电话号码,只需 :

    % 赋值

    addressMap('Charlie') = newNum;

    什么是containers.Mapcontainers.Map是一个MATLAB的内置类(类是面向对象编程中的一个基本概念,在这里可以把类暂时理解成一种数据类型),所谓内置,就是MATLAB内部实现的,通常这种类的性能更加的优秀。containers.Map其中containers是Package的名称,Map是该Package中的一个类,Map是它的类名。用UML(Unified Modeling Language)的语法把该类表示出来,它的属性包括Count, KeyType,ValueType。它的常用方法包括keys,values,isKey,remove。如图Fig.4所示。

    containers.Map的属性和成员方法

    这节我们介绍containers.Map的属性和成员方法,假设我们这样初始化一个containers.Map对象:

    % 初始化一个Map对象

    addressMap = containers.Map;

    addressMap('Abby') = '5086470001';

    addressMap('Bob') = '5086470002';

    addressMap('Charlie') = '5086470003';

    在命令行中键入该对象的名称,MATLAB会显示该对象属性的基本信息:

    >> addressMap

    addressMap =

    Map with properties:

    Count: 3 % MAP 中映射对的数目

    KeyType: char % MAP 中键的类型

    ValueType: any % MAP 中键值的类型

    其中Count 表示Map对象中映射对的数目。按照规定,键的类型一定要是字符类型,不能是其它数据类型,而键值的类型可以是MATLAB中的任意类型:数组,元胞,结构体,MATLAB对象,甚至JAVA对象等等。因为键值的类型可以是任何MATLAB类型,所以 containers.Map 是MATLAB中极其灵活的数据类型。

    成员方法keys 用来返回对象中所有的键:

    >> addressMap.keys

    ans =

    'Charlie' 'Abby' 'Bob'

    成员方法values用来返回对象中的所有键值

    >> addressMap.values

    ans =

    '5086470003' '5086470001' '5086470002'

    remove用来移除对象中的一个键-键值对,经过下面的操作之后,该对象中的Count的值变成了2。

    >> addressMap.remove('Charlie')

    ans =

    Map with properties:

    Count: 2 % 映射对数目减少

    KeyType: char

    ValueType: any

    isKey成员方法用来判断一个map对象中是否已经含有一个键值,比如:

    >> addressMap.isKey('Abby')

    ans =

    1

    >> addressMap.isKey('abby') % 键是大小写敏感的

    ans =

    0

    isKey的功能是查询,类似之前提到的find和strcmp函数合起来使用的例子。

    containers.Map的特点

    containers.Map可以不断地扩张不需预分配

    使用数组和元胞数组作为数据容器,通常要预先分配容器的大小。否则每次扩充容器,MATLAB都会重新分配内存,并且拷贝原来数组中的数据到新分配的内存中去。映射表是一个可以灵活扩充的容器,并且不需要预分配,每次往里面添加内容不会引起MATLAB重新分配内存。

    我们可以通过提供两个元胞来构造映射表对象,比如下面我们构造一个机票簿数据结构:

    % 映射表的初始化方法1

    ticketMap = containers.Map( {'2R175', 'B7398', 'A479GY'}, ...

    {'Abby', 'Bob, 'Charlie'});

    也可以在程序的一开始,先声明一个对象:

    % 映射表的初始化方法2

    >> ticketMap = containers.Map

    然后在计算的过程中慢慢的向表中插入数据:

    % 映射表的初始化方法2

    >> ticketMap['2R175'] = 'Abby';

    ...

    >> ticketMap['A479GY'] = 'Charlie;

    containers.Map可以作为参数在函数内部直接修改

    因为containers.Map是handle类(handle类的介绍参见《MATLAB面向对象编程-从入门到设计模式》第三章:MATLAB的句柄类和实值类),我们还可以方便的将这个对象传给任何MATLAB的函数,并且在函数内部直接修改对象内部的数据,并且不用把它当做返回值输出,比如:

    >> modifyMap(ticketMap);

    modifyMap函数可以写成:

    function modifyMap(ticketMap) % 该函数没有返回值

    .....

    ticketMap(NewKey) = newID

    end

    注意这里没有把修改的ticketMap当做返回值,在函数中我们直接修改了Map中的数据,这是MATLAB面向对象语言中handle类的特性。

    containers.Map可以增强程序的可读性

    映射表内部可以存储各种类型的数据,并且给它们起一些有意义的名字。具体的例子见元素周期表的例子。

    访问和修改这些数据的时候,可以直接使用这些有意义的名字,从而增加程序的可读性。而如果用元胞数组存储这些数据,在访问和修改这些数据的时候, 需要使用整数的Index,程序可读性不够好。

    containers.Map提供对数据的快速查找

    映射表查找的复杂度是常数O(C)的,而传统的数组和元胞数组查找的复杂度是线性O(N)的。如果不熟悉算法中复杂度的概念,可以这样理解:如果使用数组或者元胞来存储数据,当我们要在该数据结构中搜索一个值时,只能做线性搜索,平均下来,搜索的时间和该数据结构中的元素的数目N成正比,即元胞和数组中的元素越多,找到一个值所用的时间就越长,这叫做线性的复杂度 O(N)。而映射表采取的底层实现是哈希表(Hash Map),搜索时间是常数C,理论上来说搜索速度和集合中元素的个数没有关系。所以当容器中元素数量众多的时候,要想查找得快,可以使用containers.Map结构。具体例子见快速查找的例子。

    下面通过对假想的数据集合进行查找,来比较一下数组和container.Map的性能。我们第一行先构造一个含有1000000(10^7)个整数的数组(这是数组中元素的个数很多,如果只有少量元素,线性查找的效率会高一些),按顺序填充从1到(10^7)的整数;作为比较,第二行再构造一个containers.Map对象,往内部填充从1到(10^7)的整数,Key和KeyValue都相同。

    a = 1:1000000;

    m = containers.Map(1:1000000,ones(1,1000000));

    数组数据结构,使用find函数依次查找从1到(10^7)的整数,在笔者的机器上,耗时28.331901秒

    % array的查找

    tic

    for i=1:100000,

    find(b==i);

    end;

    toc

    % command line结果

    Elapsed time is 28.331901 seconds.

    containers.Map数据结构,使用键值1到(10^7)进行访问,

    在笔者的机器上,耗时只需1.323007秒,

    结论是:如果有大量的数据,并且要频繁的进行查找操作,可以考虑使用containers.Map数据结构。(读者可以试试减少容器中元素的个数,观察一下什么情况下,数组的查找会更快一些。)

    % 映射表的查找

    tic

    for i=1:100000,

    m(i);

    end;

    toc

    % command line结果

    Elapsed time is 1.323007 seconds.

    谈到在MATLAB中使用高级数据结构,另一种常见的做法是直接使用Java和Python对象,这里顺便比较一下在MATLAB中使用Java的哈希表的效率。再笔者的机器上,耗时3.072889秒.

    % JAVA哈希表的查找

    s = java.util.HashSet();

    for i=1:100000, s.add(i); end

    tic;

    for i=1:100000,

    s.contains(i);

    end;

    toc

    % command line结果

    Elapsed time is 3.072889 seconds.

    containers.Map的使用实例

    用来盛放元素周期表

    工程计算中可以使用这种键-键值的例子有很多。比如物理化学计算中可以用映射表来盛放元素周期表中的内容:

    >> ptable = containers.Map;

    >> ptable('H') = 1 ;

    >> ptable('He') = 2 ;

    其中键是原子符号,而键值是原子量。因为键值的类型不限,所以键值本身还可以是对象,比如Atom类对象,其中包涵更多有用的内容:

    % 类文件Atom.m

    classdef Atom < handle

    properties

    atomicNumber

    fullName

    end

    methods

    function obj = Atom(num,name)

    obj.atomicNumber = num ;

    obj.fullName = name

    end

    end

    end

    \end{Verbatim}

    于是:

    % 键值可以是Atom对象

    >> ptable('H') = Atom(1,'hydrogen');

    >> ptable('H') = Atom(2,'helium');

    用来实现快速地检索

    这个问题来自ilovematlab一个网友的提问:

    大家好,最近遇到一个问题,要构建20000次以上的三元素向量,且保证每次不重复构建,该向量元素值在2000―3000之间不定数,目前采用的方法是建立一历史档案矩阵A,构建一个存储一行,A大小行数持续增加。每次在构建出一新的向量时对该向量与历史档案矩阵每行进行对比,最终确定是否构建过,若没构建过,重新构建。算法显示该检查程序运算时间在执行20000次以上时,会超过200S的运行时间。想力争减小该时间,求方法。

    多谢!

    这位网友的问题不在于如何构建这些向量,而是如何保证每次不重复的构建。他一开始想出的解决方法是用矩阵A来存储历史档案,每建立一个新的向量,和该历史档案已有的内容做比较,如果在档案中没有存档,则构建。这样设计的问题是,如他所述,当A中存储的向量变多之后,每次检查该向量是否之前被创建过的时间加长。

    这是一个典型的可以用映射表来解决的问题,把线性的复杂度转成常数的复杂度。他可以给每个向量设计一个独立无二的ID,比如直接转数字成id : num2str(vector)% 构建

    mydictionary = containers.Map

    % 插入数据

    id = num2str(vector) ; % 比如vector = [1 2 3];

    mydictionary('some_id') = vector ;

    之后的检索也是通过vector得到独一无二的ID,然后通过isKey来判断该键值是否已经被加入到MAP中去了。

    some_otherID = some_other_vector ;

    % 验证是否已经构建给过

    if mydictinary.isKey('some_otherID')

    % 做要做的工作

    end

    关于作者oopmatlab,计算物理博士,计算机硕士,声明:

    本文内容所有内容仅代表个人观点,如有任何问题,请联系作者。

    本版块所有文章版权归作者个人所有,未经允许,不得作为出版物出版。如需转载,请联系论坛管理员。

    展开全文
    weixin_42526087 2020-12-24 18:29:48
  • 186KB m0_52957036 2020-07-09 01:16:06
  • MATLAB线性方程组的迭代求解法 作者:凯鲁嘎吉 - 博客园http://www.cnblogs.com/kailugaji/ 一、实验目的 1.借助矩阵按模最大特征值,判断解方程组的Jacobi迭代法所得迭代序列的敛散性。 2.会在Jacobi迭代法...

    MATLAB线性方程组的迭代求解法

    作者:凯鲁嘎吉 - 博客园
    http://www.cnblogs.com/kailugaji/

    一、实验目的

    1. 借助矩阵按模最大特征值,判断解方程组的Jacobi迭代法所得迭代序列的敛散性。

    2. 会在Jacobi迭代法所得迭代序列收敛时,用修改后的Gauss-Seidel迭代法。

    3. 会逐次超松驰迭代法。

    二、实验原理

    三、实验程序

    四、实验内容

    用上面前二种方法求解4元线性方程组的近似解,所选方程组尽可能可以用多种方法求得收敛解。

    注:要注意判断迭代法收敛性,方法之一就是用程序求矩阵的按模最大特征值。

    五、解答

    1.(程序)

    (1)Jacobi迭代法源程序:

    function x=jacobi(a,b,x0,n,tol,m)
    x=zeros(n,1);
    for k=0:m
        for i=1:n
            s=0;
            for j=1:n
                if j~=i
                    s=s+a(i,j)*x0(j,1);
                end
            end
            x(i,1)=(b(i,1)-s)/a(i,i);
            if norm(x-x0,inf)<tol
                break;
            end
            x0(i,1)=x(i,1);
        end
    end

    (2)Gauss-Seidel迭代法源程序:

    function x=gauss_seidel(a,b,x0,n,tol,m)
    x=zeros(n,1);
    for k=0:m
        for i=1:n
            s=0;s2=0;
            for j=1:i-1
                s2=s2+a(i,j)*x(j,1);
            end
            for j=i+1:n
                    s=s+a(i,j)*x0(j,1);
            end
            x(i,1)=(b(i,1)-s-s2)/a(i,i);
            if norm(x-x0,inf)<tol
                break;
            end
            x0(i,1)=x(i,1);
        end
    end

    2.(运算结果)

    (1)求解线性方程组

    >> a=[8 -3 2;4 11 -1;6 3 12];b=[20 33 36]';x0=[0 0 0]';
    >> x=jacobi(a,b,x0,3,1e-6,50)
    
    x =
    
        3.0000
        2.0000
        1.0000

    (2)Gauss-Seidel迭代法

    >>  a=[8 -3 2;4 11 -1;6 3 12];b=[20 33 36]';x0=[0 0 0]';
    >> x=gauss_seidel(a,b,x0,3,1e-6,50)
    
    x =
    
        3.0000
        2.0000
        1.0000

    3.(拓展(方法改进、体会等))

    逐次超松驰迭代法源程序:

    function x=SOR(a,b,x0,n,w,tol,m)
    x=zeros(n,1);
    for k=0:m
        for i=1:n
            s=0;s2=0;
            for j=1:i-1
                s2=s2+a(i,j)*x(j,1);
            end
            for j=i+1:n
                    s=s+a(i,j)*x0(j,1);
            end
            x(i,1)=(1-w)*x0(i,1)+w*(b(i,1)-s-s2)/a(i,i);
            if norm(x-x0,inf)<tol
                break;
            end
            x0(i,1)=x(i,1);
        end
    end

    运算结果:

    >>  a=[-4 1 1 1;1 -4 1 1;1 1 -4 1;1 1 1 -4];b=[1 1 1 1]';x0=[0 0 0 0]';
    >> x=SOR(a,b,x0,4,1,1e-6,20)
    
    x =
    
       -1.0000
       -1.0000
       -1.0000
       -1.0000

     

    转载于:https://www.cnblogs.com/kailugaji/p/6932399.html

    展开全文
    difei1877 2019-09-25 07:01:22
  • 这个由于计算较为繁琐,我们可以交给MATLAB完成,使用eig命令既可以计算特征值,也可以计算特征向量。 当最大特征值等于矩阵阶数的时候,我们的正互反矩阵才为一致矩阵: 当最大特征值与n相差越大时,我们得到的...

    其主要用于解决评价类问题(例如:选择哪种方案最好、哪位运动员或者员工表现的更优秀)

    一个很典型的层次分析法案例:

    确定评价目标:

    高考完后小明想要去旅游,有三个目的地供他选择:

    苏杭

    北戴河

    桂林

    确定评价准则:

    假如小明要选择目的地,他同时考虑以下的条件,我们称为评价准则:

    景色

    花费

    居住

    饮食

    交通

    确定评价准则的判断矩阵:

    在这之前,我们要介绍一下重要程度表:

    当两个条件互相比较时,谁比谁重要,可以用这张表的数值(1~9)来进行打分。

    我们要依次确定这个五个条件的权重以便小明选择目的地,假如我们问小明:

    博主:”小明,你觉得这五个条件对你来说对于选择目的地来说更重要啊?“

    小明:”一次让我来说的话可能不太好判断,每个我感觉都挺重要啊。。。“

    于是我们就会遇到这样的问题,但条件很多时,我们就不好一下子直接说出哪一个条件对于目的地的选择更加重要(或者说在小明心中的权重)。所以这个时候我们可以构造一个表格来两两比较:

    观察以上表格,分成三个部分:

    对角线以上

    拿景色与花费做例子,景色相比与花费,小明觉得景色对于他来说要求不是那么高,反而会更在意花费,所以景色相对于花费的值是1/2

    对角线

    由于表格的对角线是条件与自己相比,所以值为1(同等重要)

    对角线以下

    既然对角线以上是景色比花费,那么对角线就是花费比景色,正好相反

    所以我们看到,对角线以下的是对角线以上的倒数,由于有五个评价准则,所以一共要两两比较:

    次就可以填满整张表。

    下面是结果:

    总结:上面的上面这个表是一个5 X 5的方阵,我们记为A,对应的元素为:

    这个方阵有如下特点:

    aij的意思是i与指标𝑗相比,𝑖的程度

    当𝑖 = 𝑗时,两个指标相同,因此同等重要记为1,这就解释了主对角线元素为1。

    𝑎ij> 0且满足𝑎ij X 𝑎ji = 1 (我们称满足这一条件的矩阵为正互反矩阵)

    上面这个矩阵就是层次分析法中的判断矩阵,得到了判断矩阵,就可以计算出权重了

    确定目标的判断矩阵:

    既然评价准则之间有判断矩阵,在小明心中,对于景色来说,苏杭,北戴河,桂林之间可能也有不同的分数,他可能觉得在景色方面,桂林更胜一筹,那么桂林的分数就要比其它两个的分数要高,那这样单单就景色来说,苏杭,北戴河,桂林之间就要两两之间进行比较,其它的条件也是同样如此,于是我们可以类比以上的表格:

    景色:

    花费

    居住

    饮食

    交通

    一致矩阵的概念

    由于以上表格都是我们问,小明答,有很强的主观意愿,所以这张表表格很可能出错,下面我们就来看一个错误的例子:

    如上图所示,出现了不一致的现象,那么我们来看一个一致的矩阵:

    我们观察这个矩阵,它的各行各列成比例,我们称这个矩阵为一致矩阵,我们可以用数学符号来表达:

    所以,综上所述:各行(各列)之间成倍数关系的矩阵为一致矩阵。

    总结:

    矩阵中每个元素都大于0且对角线元素为1的矩阵我们成为正互反矩阵

    在层次分析法中,我们构造的判断矩阵都是正互反矩阵

    若正互反矩阵满足各行各列成比例,我们称为一致矩阵

    所以,我们得到的判断矩阵一定是正互反矩阵,由于跟实际情况中可变的因素有很多,所以我们的正互反矩阵在现实生活中很难满足各行各列成比例,所以也就很难让正互反矩阵成为一致矩阵,但是我们可以对正互反矩阵进行一致性检验,让它在一定的范围误差内,在此误差内我们可以看作其满足一致性矩阵的条件,所以我们在得到了判断矩阵(正互反矩阵)后要进行一致性检验

    对判断矩阵进行一致性检验:

    原理: 检验我们构造的判断矩阵和一致矩阵是否有太大的差别。

    一致性检验的步骤:

    计算判断矩阵的特征值:

    如果特征值中有虚数,则比较的是特征值的模长。

    这个由于计算较为繁琐,我们可以交给MATLAB完成,使用eig命令既可以计算特征值,也可以计算特征向量。

    当最大特征值等于矩阵阶数的时候,我们的正互反矩阵才为一致矩阵:

    当最大特征值与n相差越大时,我们得到的矩阵越不一致。

    计算一致性指标CI:

    查找对应的平均随机一致性指标RI:

    注:在实际运用中,n很少超过10,如果指标的个数大于10,则可考虑建立 二级指标体系,或使用我们以后要学习的模糊综合评价模型。

    计算一致性比例CR:

    对一致性比例CR进行判断:

    如果CR<0.1,则判断矩阵的一致性可以接受。

    如果CR>0.1,则要对判断矩阵进行修正。

    计算判断矩阵的权重:

    计算权重有三种方法:

    算数平均法求权重:

    步骤:

    将判断矩阵按照列归一化(每一个元素除以其所在列的和)

    我们看一个例子:

    第一列:

    第二列:

    第三列:

    于是我们得到以下表格:

    将归一化的各行相加:

    相加后我们得到以下表格:

    除以n得到最后的权重

    几何平均法求权重:

    步骤:

    将A的元素按照行相乘得到一个新的列向量

    在MATLAB中使用prod(A,2)命令即可以对一行进行相乘

    A =

    1.0000 2.0000 5.0000

    0.5000 1.0000 2.0000

    0.2000 0.5000 1.0000

    使用prod(A,2)命令:

    >> prod(A,2)

    ans =

    10.0000

    1.0000

    0.1000

    将新的向量的每个分量开n次方

    >> ans.^(1/3)

    ans =

    2.1544

    1.0000

    0.4642

    对该列向量进行归一化即可得到权重向量

    结果:

    注: 权重和应为1,这里由于四舍五入所以会有可以忽略的差距。

    特征值法求权重:

    步骤:

    1.在MATLAB中使用eig命令求特征值和特征向量:

    A =

    1.0000 2.0000 5.0000

    0.5000 1.0000 2.0000

    0.2000 0.5000 1.0000

    >> [v,r] = eig(A)

    v =

    -0.8902 + 0.0000i -0.8902 + 0.0000i -0.8902 + 0.0000i

    -0.4132 + 0.0000i 0.2066 + 0.3578i 0.2066 - 0.3578i

    -0.1918 + 0.0000i 0.0959 - 0.1661i 0.0959 + 0.1661i

    r =

    3.0055 + 0.0000i 0.0000 + 0.0000i 0.0000 + 0.0000i

    0.0000 + 0.0000i -0.0028 + 0.1290i 0.0000 + 0.0000i

    0.0000 + 0.0000i 0.0000 + 0.0000i -0.0028 - 0.1290i

    找出最大特征值为3.0055

    2. 对求出的特征向量进行归一化即可得到我们的权重:

    最大特征值对应的特征向量

    -0.8902 + 0.0000i

    -0.4132 + 0.0000i

    -0.1918 + 0.0000i

    归一化:

    0.5954

    0.2764

    0.1283

    三种方法计算的权重结果:

    将计算结果填入权重表,得到:

    计算评价准则的权重:

    得到评价准则的判断矩阵:

    用三种方法计算权重:

    填入表格:

    求出其它评价准则对应的权重:

    汇总结果得到权重矩阵:

    根据权重表格计算每个目标的得分:

    类似我们求出:

    结果:

    因此最佳的旅游景点是桂林

    总结:

    1.建立层次结构:

    2.构造准则层之间判断矩阵:

    3.构造方案层之间判断矩阵:

    4.对以上每个判断矩阵进行一致性检验(通过后才能计算权重):

    5.通过检验后根据权重矩阵计算得分,并进行排序

    三种方法计算权重:

    注意事项:

    一致矩阵不需要进行一致性检验,只有非一致矩阵的判断矩阵才需要进行一致性检验

    在论文写作中,应该先进行一致性检验,通过检验后再计算权重,以上讲解的只是为了顺应计算过程。

    特征值可用MATLAB进行计算,如果特征值中有虚数,则比较的是特征值的模长。

    如果CR > 0.1 ,我们可以往一致矩阵上调整(这个就看你自己了,反正评委也不知道是吧~)

    平均随机一致性指标RI的表格中n最多是15

    层次分析法的一些局限性:

    评价的准则层n不能太多(一般不超过十个),太多的话n(最多是15)会很大,判断矩阵和一致矩阵差异可能会很大。

    代码(含有详细注释):

    disp('请输入判断矩阵A')

    A=input('A=');

    [n,n] = size(A);

    % % % % % % % % % % % % %方法1: 算术平均法求权重% % % % % % % % % % % % %

    Sum_A = sum(A);

    SUM_A = repmat(Sum_A,n,1);

    Stand_A = A ./ SUM_A;

    disp('算术平均法求权重的结果为:');

    disp(sum(Stand_A,2)./n)

    % % % % % % % % % % % % %方法2: 几何平均法求权重% % % % % % % % % % % % %

    Prduct_A = prod(A,2);

    Prduct_n_A = Prduct_A .^ (1/n)

    disp('几何平均法求权重的结果为:');

    disp(Prduct_n_A ./ sum(Prduct_n_A))

    % % % % % % % % % % % % %方法3: 特征值法求权重% % % % % % % % % % % % %

    [V,D] = eig(A);

    Max_eig = max(max(D));

    [r,c]=find(D == Max_eig , 1);

    disp('特征值法求权重的结果为:');

    disp( V(:,c) ./ sum(V(:,c)) )

    % % % % % % % % % % % % %下面是计算一致性比例CR的环节% % % % % % % % % % % % %

    CI = (Max_eig - n) / (n-1);

    RI=[0 0.0001 0.52 0.89 1.12 1.26 1.36 1.41 1.46 1.49 1.52 1.54 1.56 1.58 1.59]; %注意哦,这里的RI最多支持 n = 15

    % 这里n=2时,一定是一致矩阵,所以CI = 0,我们为了避免分母为0,将这里的第二个元素改为了很接近0的正数

    CR=CI/RI(n);

    disp('一致性指标CI=');disp(CI);

    disp('一致性比例CR=');disp(CR);

    if CR<0.10

    disp('因为CR<0.10,所以该判断矩阵A的一致性可以接受!');

    else

    disp('注意:CR >= 0.10,因此该判断矩阵A需要进行修改!');

    end

    可以参考的矩阵:

    将以下五个矩阵依次输入以上代码中就可以直接求出各种结果

    评价准则:

    [1, 1/2, 4, 3, 3;

    2, 1, 7, 5, 5;

    1/4, 1/7, 1, 1/2, 1/3;

    1/3, 1/5, 2, 1, 1;

    1/3, 1/5, 3, 1, 1]

    景色:

    [1,2,5;

    1/2,1,2;

    1/5,1/2,1;]

    花费:

    [1,1/3,1/8;

    3,1,1/3;

    8,3,1;]

    居住:

    [1,1,3;

    1,1,3;

    1/3,1/3,1;]

    饮食:

    [1,3,4;

    1/3,1,1;

    1/4,1,1;]

    交通 :

    [1,1,1/4;

    1,1,1/4;

    4,4,1;]

    展开全文
    weixin_42378094 2020-12-24 18:30:01
  • MATLAB常用基本数据类型有:整型,浮点型,字符型,函数句柄,元胞数组和结构体数组。除了这些基本数据类型,MATLAB还有很多其它的数据类型不为人熟悉,这些数据类型在编程中也非常有用。MATLAB高级数据类型系列旨在...

    MATLAB常用基本数据类型有:整型,浮点型,字符型,函数句柄,元胞数组和结构体数组。除了这些基本数据类型,MATLAB还有很多其它的数据类型不为人熟悉,这些数据类型在编程中也非常有用。MATLAB高级数据类型系列旨在向大家介绍它们:比如containers.Map,tables,enumeration和time

    series等等,它们为什么有用,用来解决什么问题,并且怎样在科学工程计算使用。本篇首先介绍containers.Map数据类型。

    containers.Map简介

    MATLAB中最具代表性的高级数据类型是containers.Map,我们可以把它叫做映射表。它和函数映射有些类似,比如函数映射的定义是:

    F(x) = Y

    针对每一个X,都有一个唯一的Y与之对应,反之不一定。如图Fig.1所示。和函数映射相似,映射表用来形容键(Key)和键值(Key

    Value)之间的一一对应关系。每个Key都是独一无二的,且只能对一个Key

    Value。如图Fig.2所示。

    Fig.1

    函数映射关系

    Fig.2

    containers.Map类的映射示意图

    数组,元胞和结构体的局限性

    开始我们先介绍一下数组,元胞数组和结构体的局限性,为什么有的时候这些基本的数据类型无法满足程序的要求,换句话说,我们为什么需要containers.Map数据结构。假设要用MATLAB来记录电话号码簿中数据,比如表Table.1所示:

    Table.1 电话号码簿

    姓名

    电话号码

    Abby

    5086470001

    Bob

    5086470002

    Charlie

    5086470003

    先讨论数组,因为电话号码簿中既含有数字,又含有字符串,而数组中只能存放Double类型的数据,所以没有办法用数组直接记录电话号码薄中的内容。

    再试试元胞数组,我们在第1行预先声明一个3

    X 3的元胞数组,然后在2-4行按顺序填放号码簿的内容。

    % 元胞数组初始化

    addressBook

    = cell(3,1);

    % 预分配大小是MATLAB编程的好习惯

    addressBook{1}

    = {'Abby',

    '5086470001'};

    addressBook{2}

    = {'Bob'

    , '5086470002'};

    addressBook{3}

    = {'Charlie',

    '5086470003'};

    需要的时候,可以通过for循环访问其中的内容,比如:

    for iter

    = 1:length(addressBook)

    % 元胞数组的遍历

    addressBook{iter}

    % 通过Index访问元胞中的内容

    end

    但是按照顺序遍历电话号码簿没有什么实际用处,号码簿的主要功能应该是提供查找的功能才是。比如要想查询Charlie的电话号码,我们希望程序最好可以写成如下这样:

    CharlieNum

    = addressBook{'Charlie'}

    % 提示:这是错误的写法

    或者

    CharlieNum

    = addressBook.Charlie

    % 提示:这是错误的写法

    但是元胞数组的值只能通过Index去访问内容,不支持如上的访问方式。所以为了找到Charlie的电话号码,程序不得不遍历元胞中的所有内容,取出每一个元胞元素的第一列的字符串做比较,如果名字等于Charlie,则输出电话号码:

    % 使用for循环查找

    for iter

    = 1:length(addressBook)

    if strcmp(addressBook{iter}{1},'Charlie')

    addressBook{iter}{2}

    % 如找到则输出电话号码

    break;

    end

    end

    当然还有其他的方式来盛放电话号码簿,比如把电话和名字分别存到到两个元胞数组中去

    names

    = {'Abby','Bob','Charlie'};

    % 用元胞放号码

    numbers

    = {'5086470001','5086470002','5086470001'};

    % 用元胞放名字

    ind

    = find(strcmp(names,'Charlie'));

    % strcmp接受向量的输入 返回Logical数组

    % find紧接着找出逻辑数组中非零元素的Index

    numbers{ind}

    其中第3行strcmp接受元胞作为输入,在其中寻找Charlie,find函数将返回Charlie所在的位置,这样的方式比使用for循环要快,但无一例外的是,两种方法都要从头开始遍历一个数组,终究来说是慢的。

    除查找性能慢外,使用元胞盛放电话号码簿类型的数据还有其它缺点:

    无法方便的验证重复数据。电话号码簿要求每一个人的名字都是独一无二的,所以在数据录入的时候要防止姓名的重复,但是我们没有其它办法知道某名字是否已经被使用过了,除非在每次输入的时候都对整个元胞里的内容做遍历比较。

    无法方便地添加内容。如果电话号码簿中的记录需要不断地增长,但是我们没有办法在一开始就估计出其大概的数量,于是无法有效的预先分配内存,所以添加数据时,一旦超过预先分配的量,MATLAB就要重新分配内存了。

    无法方便地删除内容。如果我们要从元胞中去掉某一记录,可以找到该记录,并把该位置的元胞内容置空,但这并不会自动减小元胞数组的长度,如果

    这样的删减操作多了,元胞中会留下很多没有利用的空余位置。

    不方便作为函数的参数,具体原因见struct的局限性.

    最后我们再尝试一下用结构体盛放电话号码簿数据类型,struct的赋值很简单,比如可以直接赋值:

    % 赋值方法1

    addressBook.Abby

    = '5086470001';

    addressBook.Bob

    = '5086470002';

    addressBook.Charlie

    = '5086470003';

    或者:

    % 赋值方法2

    addressBook

    = struct('Abby','5086470001','Bob','5086470002','Charlie','5086470003')

    方法1和方法2是等价的。

    struct数据类型的查找很方便,比如要查询Charlie的电话号码,直接访问struct中的同名的field即可以了。

    num

    = addressBook.Charlie

    如果要查询的人名是一个变量,

    我们可以使用getfield函数:

    num

    = getfield(addressBook,name)

    % 其中name是变量

    struct盛放电话号码簿类型的数据,查询起来确实比元胞进步了不少,但还是有些不方便的地方。

    因为struct的field的名字要求必须是以字母开头,这是一个很大的局限,并不是所有的类似电话号码簿的结构都可以用人名做索引,比如账户号码簿,股票代码等等,他们通常是用数字开头的,比如图Table.2中的数据:

    Table.2 深证股票代码

    股票代码

    股票名称

    000001

    深发展

    000002

    万科

    000004

    ST国农

    如果我们要求通过股票的代码来查找股票的具体信息,struct无法简单的直接做到。

    使用struct的另一个不方便之处在于,当把struct当做函数参数,并且在函数内部需要对该struct做一定的修改时,为了要把修改后的结果返回,我们需要对原来的struct做完全的拷贝,显然如果struct中的数据很多的话,这样做是低效的。比如下面的函数中,addressBook被当做函数的参数传入,在函数中添加了一个新的field,

    为了返回更新后的结构,函数内部必须重新构造一个新的struct,也就是s返回给该函数的调用者。

    % 把struct当做函数的参数

    function s

    = modifystruct(s)

    s.Dave

    = '5086470004';

    end

    用containers.Map来记录电话号码簿

    上面一节我们介绍了数组,元胞数组和结构体在模拟电话号码簿这种数据结构时的局限性,这节我们来看怎么用containers.Map来盛放电话号码簿中的内容:

    addressMap

    = containers.Map;

    % 首先声明一个映射表对象变量

    addressMap('Abby')

    = '5086470001';

    addressMap('Bob')

    = '5086470002';

    addressMap('Charlie')

    = '5086470003';

    第一行我们声明一个containers.Map的变量(其实是containers.Map类的对象)叫做addressMap,2,3,4行通过提供Key

    Key Value的方式来给对象赋值,其中单引号内部的值叫做键(Key),等式右边的叫做键值(Key

    Value)。通过这个结构,我们在MATLAB内存中,建立起了如图Fig.3的映射关系数据结构。

    Fig.3

    电话号码簿映射表

    Fig.4

    Map类的UML

    查找addressMap对象中的内容极其方便,比如查找我们想知道Charlie的电话号码,只需:

    % 查找

    num

    = addressMap('Charlie')

    如果我们要修改Charlie的电话号码,只需

    % 赋值

    addressMap('Charlie')

    = newNum;

    什么是containers.Map

    containers.Map是一个MATLAB的内置类(类是面向对象编程中的一个基本概念,在这里可以把类暂时理解成一种数据类型),所谓内置,就是MATLAB内部实现的,通常这种类的性能更加的优秀。containers.Map其中containers是Package的名称,Map是该Package中的一个类,Map是它的类名。用UML(Unified

    Modeling Language)的语法把该类表示出来,它的属性包括Count,

    KeyType,ValueType。它的常用方法包括keys,values,isKey,remove。如图Fig.4所示。

    containers.Map的属性和成员方法

    这节我们介绍containers.Map的属性和成员方法,假设我们这样初始化一个containers.Map对象:

    % 初始化一个Map对象

    addressMap

    = containers.Map;

    addressMap('Abby')

    = '5086470001';

    addressMap('Bob')

    = '5086470002';

    addressMap('Charlie')

    = '5086470003';

    在命令行中键入该对象的名称,MATLAB会显示该对象属性的基本信息:

    >>

    addressMap

    addressMap

    =

    Map

    with

    properties:

    Count:

    3 % MAP 中映射对的数目

    KeyType:

    char % MAP 中键的类型

    ValueType:

    any

    % MAP 中键值的类型

    其中Count

    表示Map对象中映射对的数目。按照规定,键的类型一定要是字符类型,不能是其它数据类型,而键值的类型可以是MATLAB中的任意类型:数组,元胞,结构体,MATLAB对象,甚至JAVA对象等等。因为键值的类型可以是任何MATLAB类型,所以containers.Map是MATLAB中极其灵活的数据类型。

    成员方法keys 用来返回对象中所有的键:

    >>

    addressMap.keys

    ans

    =

    'Charlie' 'Abby' 'Bob'

    成员方法values用来返回对象中的所有键值

    >>

    addressMap.values

    ans

    =

    '5086470003' '5086470001' '5086470002'

    remove用来移除对象中的一个键-键值对,经过下面的操作之后,该对象中的Count的值变成了2。

    >>

    addressMap.remove('Charlie')

    ans

    =

    Map

    with

    properties:

    Count:

    2 % 映射对数目减少

    KeyType:

    char

    ValueType:

    any

    isKey成员方法用来判断一个map对象中是否已经含有一个键值,比如:

    >>

    addressMap.isKey('Abby')

    ans

    =

    1

    >>

    addressMap.isKey('abby')

    % 键是大小写敏感的

    ans

    =

    0

    isKey的功能是查询,类似之前提到的find和strcmp函数合起来使用的例子。

    containers.Map的特点

    containers.Map可以不断地扩张不需预分配

    使用数组和元胞数组作为数据容器,通常要预先分配容器的大小。否则每次扩充容器,MATLAB都会重新分配内存,并且拷贝原来数组中的数据到新分配的内存中去。映射表是一个可以灵活扩充的容器,并且不需要预分配,每次往里面添加内容不会引起MATLAB重新分配内存。

    我们可以通过提供两个元胞来构造映射表对象,比如下面我们构造一个机票簿数据结构:

    % 映射表的初始化方法1

    ticketMap

    = containers.Map(

    {'2R175',

    'B7398',

    'A479GY'},

    ...

    {'Abby',

    'Bob, 'Charlie'});

    也可以在程序的一开始,先声明一个对象:

    % 映射表的初始化方法2

    >>

    ticketMap

    = containers.Map

    然后在计算的过程中慢慢的向表中插入数据:

    % 映射表的初始化方法2

    >>

    ticketMap['2R175']

    = 'Abby';

    ...

    >>

    ticketMap['A479GY']

    = 'Charlie;

    containers.Map可以作为参数在函数内部直接修改

    因为containers.Map是handle类(handle类的介绍参见《MATLAB面向对象编程-从入门到设计模式》第三章:MATLAB的句柄类和实值类),我们还可以方便的将这个对象传给任何MATLAB的函数,并且在函数内部直接修改对象内部的数据,并且不用把它当做返回值输出,比如:

    >>

    modifyMap(ticketMap);

    modifyMap函数可以写成:

    function modifyMap(ticketMap)

    % 该函数没有返回值

    .....

    ticketMap(NewKey)

    = newID

    end

    注意这里没有把修改的ticketMap当做返回值,在函数中我们直接修改了Map中的数据,这是MATLAB面向对象语言中handle类的特性。

    containers.Map可以增强程序的可读性

    映射表内部可以存储各种类型的数据,并且给它们起一些有意义的名字。具体的例子见元素周期表的例子。

    访问和修改这些数据的时候,可以直接使用这些有意义的名字,从而增加程序的可读性。而如果用元胞数组存储这些数据,在访问和修改这些数据的时候,

    需要使用整数的Index,程序可读性不够好。

    containers.Map提供对数据的快速查找

    映射表查找的复杂度是常数O(C)的,而传统的数组和元胞数组查找的复杂度是线性O(N)的。如果不熟悉算法中复杂度的概念,可以这样理解:如果使用数组或者元胞来存储数据,当我们要在该数据结构中搜索一个值时,只能做线性搜索,平均下来,搜索的时间和该数据结构中的元素的数目N成正比,即元胞和数组中的元素越多,找到一个值所用的时间就越长,这叫做线性的复杂度

    O(N)。而映射表采取的底层实现是哈希表(Hash

    Map),搜索时间是常数C,理论上来说搜索速度和集合中元素的个数没有关系。所以当容器中元素数量众多的时候,要想查找得快,可以使用containers.Map结构。具体例子见快速查找的例子。

    下面通过对假想的数据集合进行查找,来比较一下数组和container.Map的性能。我们第一行先构造一个含有1000000(10^7)个整数的数组(这是数组中元素的个数很多,如果只有少量元素,线性查找的效率会高一些),按顺序填充从1到(10^7)的整数;作为比较,第二行再构造一个containers.Map对象,往内部填充从1到(10^7)的整数,Key和KeyValue都相同。

    a

    = 1:1000000;

    m

    = containers.Map(1:1000000,ones(1,1000000));

    数组数据结构,使用find函数依次查找从1到(10^7)的整数,在笔者的机器上,耗时28.331901秒

    % array的查找

    tic

    for i=1:100000,

    find(b==i);

    end;

    toc

    % command line结果

    Elapsed

    time

    is

    28.331901 seconds.

    containers.Map数据结构,使用键值1到(10^7)进行访问,

    在笔者的机器上,耗时只需1.323007秒,

    结论是:如果有大量的数据,并且要频繁的进行查找操作,可以考虑使用containers.Map数据结构。(读者可以试试减少容器中元素的个数,观察一下什么情况下,数组的查找会更快一些。)

    % 映射表的查找

    tic

    for i=1:100000,

    m(i);

    end;

    toc

    % command line结果

    Elapsed time is 1.323007 seconds.

    谈到在MATLAB中使用高级数据结构,另一种常见的做法是直接使用Java和Python对象,这里顺便比较一下在MATLAB中使用Java的哈希表的效率。再笔者的机器上,耗时3.072889秒.

    % JAVA哈希表的查找

    s

    = java.util.HashSet();

    for i=1:100000,

    s.add(i);

    end

    tic;

    for i=1:100000,

    s.contains(i);

    end;

    toc

    % command line结果

    Elapsed

    time

    is

    3.072889 seconds.

    containers.Map的使用实例

    用来盛放元素周期表

    工程计算中可以使用这种键-键值的例子有很多。比如物理化学计算中可以用映射表来盛放元素周期表中的内容:

    >>

    ptable

    = containers.Map;

    >>

    ptable('H')

    = 1 ;

    >>

    ptable('He')

    = 2 ;

    其中键是原子符号,而键值是原子量。因为键值的类型不限,所以键值本身还可以是对象,比如Atom类对象,其中包涵更多有用的内容:

    % 类文件Atom.m

    classdef Atom

    < handle

    properties

    atomicNumber

    fullName

    end

    methods

    function obj

    = Atom(num,name)

    obj.atomicNumber

    = num

    ;

    obj.fullName

    = name

    end

    end

    end

    \end{Verbatim}

    于是:

    % 键值可以是Atom对象

    >>

    ptable('H')

    = Atom(1,'hydrogen');

    >>

    ptable('H')

    = Atom(2,'helium');

    用来实现快速地检索

    这个问题来自ilovematlab一个网友的提问:

    大家好,最近遇到一个问题,要构建20000次以上的三元素向量,且保证每次不重复构建,该向量元素值在2000―3000之间不定数,目前采用的方法是建立一历史档案矩阵A,构建一个存储一行,A大小行数持续增加。每次在构建出一新的向量时对该向量与历史档案矩阵每行进行对比,最终确定是否构建过,若没构建过,重新构建。算法显示该检查程序运算时间在执行20000次以上时,会超过200S的运行时间。想力争减小该时间,求方法。

    多谢!

    这位网友的问题不在于如何构建这些向量,而是如何保证每次不重复的构建。他一开始想出的解决方法是用矩阵A来存储历史档案,每建立一个新的向量,和该历史档案已有的内容做比较,如果在档案中没有存档,则构建。这样设计的问题是,如他所述,当A中存储的向量变多之后,每次检查该向量是否之前被创建过的时间加长。

    这是一个典型的可以用映射表来解决的问题,把线性的复杂度转成常数的复杂度。他可以给每个向量设计一个独立无二的ID,比如直接转数字成id

    :num2str(vector)

    % 构建

    mydictionary

    = containers.Map

    % 插入数据

    id

    = num2str(vector)

    ; % 比如vector = [1 2 3];

    mydictionary('some_id')

    = vector

    ;

    之后的检索也是通过vector得到独一无二的ID,然后通过isKey来判断该键值是否已经被加入到MAP中去了。

    some_otherID

    = some_other_vector

    ;

    % 验证是否已经构建给过

    if mydictinary.isKey('some_otherID')

    % 做要做的工作

    end

    展开全文
    weixin_39627665 2020-12-24 18:29:24
  • weixin_44690935 2020-05-20 15:11:04
  • 17KB weixin_38670297 2021-06-08 07:13:22
  • dollar_jen 2021-04-22 22:16:53
  • Ricardo1998 2020-10-27 17:43:25
  • dollar_jen 2021-03-21 09:16:40
  • 563KB songweizhi 2019-06-19 19:01:25
  • weixin_29895109 2021-04-20 00:41:52
  • 573KB m0_52957036 2020-09-28 10:57:46
  • 275KB weixin_38690376 2021-06-01 12:03:40
  • weixin_34094559 2021-04-20 05:01:54
  • 5星
    33KB yimi1210 2011-09-23 20:53:33
  • u014030117 2015-06-04 20:40:45
  • 3KB weixin_38659527 2021-05-29 20:29:08
  • 37KB alice9182736455 2013-07-05 12:24:18
  • xiong_xin 2020-07-03 22:56:19
  • weixin_36275231 2021-04-26 11:47:11
  • 4KB weixin_38523618 2021-05-31 14:06:53
  • 2KB weixin_38620893 2021-06-01 13:49:08
  • 10KB weixin_38575421 2021-06-01 11:38:58
  • 26KB weixin_38536397 2021-05-29 18:56:13
  • weixin_42129435 2021-06-18 22:05:05
  • weixin_39692623 2021-04-22 06:53:36
  • 2KB weixin_38657835 2021-06-01 19:32:51
  • 47KB pengheartoh 2016-06-13 11:52:29
  • qq_20823641 2016-06-19 11:21:13

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,489
精华内容 4,595
关键字:

matlab线性映射

matlab 订阅