精华内容
下载资源
问答
  • 行业文档-设计装置-一种用于双向组合式造纸增强工艺的装置.zip
  • NULL 博文链接:https://dreamzhong.iteye.com/blog/1201459
  • 研究了多物品拍卖机制,建立了多物品双向拍卖模型,针对其算法的求解困难,设计了一种启发式算法。模型的应用具有一定的灵活性,即不同的函数形式可以通过转化变换为模型的形式来求解,使复杂的求解问题得到了简化。
  • 基于组合双向拍卖的网格定价算法,丁鹏,马晓雷,针对网格环境中资源分配的特点,以网格经济中的组合双向拍卖模型为基础,分析传统组合双向拍卖模型中的优缺点,提出了一种新的组
  • 在UML类图中,类之间的关系可以分成:关联(association)、聚合(aggregation)、组合(composition)、依赖(dependency)、泛化(generalization)/继承(inheritance)和实现(realization)。这六种关系如下图所描绘: &...

    一、类的属性的表示方式

    在UML类图中,类使用包含类名、属性(field) 和方法(method) 且带有分割线的矩形来表示,比如下图表示一个A类,它包含c、d两个属性,以及methodA方法。
    在这里插入图片描述
    那么属性/方法名称前加的加号和减号是什么意思呢?它们表示了这个属性或方法的可见性,UML类图中表示可见性的符号有三种:

    · + :表示public

    · - :表示private

    · #:表示protected(friendly也归入这类)
    属性的完整表示方式如下:
    可见性 名称 :类型 [ = 缺省值]

    方法的完整表示方式如下:
    可见性 名称(参数列表) [ : 返回类型]

    属性与方法中括号中的内容是可选的。

    一、简介
    在UML类图中,类之间的关系可以分成:关联(association)、聚合(aggregation)、组合(composition)、依赖(dependency)、泛化(generalization)/继承(inheritance)和实现(realization)。这六种关系如下图所描绘:
    在这里插入图片描述
    上面的关系可以解读如下:
    (关联)Association:A类有B类有逻辑上的连接
    (聚合)Aggregation : A类有一个B类
    (组合)Composition : A类拥有一个B类
    (依赖)Dependency : A类使用了B类
    (继承)Inheritance : B类是一个A类 (或者B类扩展A类)
    (实现)Realization : B类实现了接口A
    本篇文章主要是展示在Java中如何表示这些关系 ,以便我们可以更好地理解这些关系并且知道如何以及何时使用每一种关系。

    二、关联(association)
    关联描述两个类之间行为的一般二元关系。例如,一个学生选修一门特定的课程是学生类Student和课程类Course之间的一个关联,而一个教师教授一门课程是师资类Faculty和课程类Course之间的一个关联。Java代码中,关联可以用属性和方法来实现。

    public class Student {
        private Course[] courses;
    
              
        public void addCourse(Course s) {
            . . . . . .
        } }
    
    public class Course {
        private Strudent[] students;
        private Faculty faculty;
    
        public void addStudent(Student s) {
            . . . . . .
        }
    
        public void setFaculty(Faculty faculty) {
            this.faculty = faculty;
        } }
    
    public class Faculty {
        private Course[] courses;
               
        public void addCourse(Course s) {
            . . . . . .
        }  }
    

    三、聚合(Aggregation)
    聚合是一种特殊的关联(Association)形式,表示两个对象之间的所属(has-a)关系。所有者对象称为聚合对象,它的类称为聚合类;从属对象称为被聚合对象,它的类称为被聚合类。例如,一个公司有很多员工就是公司类Company和员工类Employee之间的一种聚合关系。被聚合对象和聚合对象有着各自的生命周期,即如果公司倒闭并不影响员工的存在。

    
    public class Company {
        private List<Employee> employees;
    }
    
    public class Employee {
        private String name;   
    }
    

    四、组合(Composition)
    聚合是一种较弱形式的对象包含(一个对象包含另一个对象)关系。较强形式是组合(Composition). 在组合关系中包含对象负责被包含对象的创建以及生命周期,即当包含对象被销毁时被包含对象也会不复存在。例如一辆汽车拥有一个引擎是汽车类Car与引擎类Engine的组合关系。下面是组合的一些例子。

       (1)通过成员变量初始化   
    
    public class Car {
        private final Engine engine = new Engine();       
    }
    
    class Engine {
        private String type;
    }
    
      (2)通过构造函数初始化  
    
    public class Car {
        private final Engine engine;  
           
        public Car(){
           engine  = new Engine();
        }
    }
    
    public class Engine {
        private String type;
    }
    
      (3)通过延迟初始化
    
    public class Car {	
        private final Engine engine;  
        public Engine getEngine() {
            if (null == engine) {
                engine = new Engine();
            }
            return engine;
        }     
    }
    
    public class Engine {
        private String type;
    }
    

    五、依赖(Dependency)
    依赖(Dependency)描述的是一个类的引用用作另一个类的方法的参数。例如,可以使用Calendar类中的setTime(Date date)方法设置日历,所以Calendar和Date之间的关系可以用依赖描述。

    public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
    
        public final void setTime(Date date) {
            setTimeInMillis(date.getTime());
        }
          
        . . . . . .
    }
    
       在依赖关系中,类之间是松耦合的。
    

    六、继承(Inheritance)
    继承(Inheritance)模拟两个类之间的is-a关系。强是(strong is-a)关系描述两个类之间的直接继承关系。弱是(weak is-a)关系描述一个类具有某个属性。强是关系可以用类的继承表示。例如,Spring的ApplicationEvent是一个EventObject,ApplicationEvent和EventObject间就是一种强是关系,可以用继承描述。

    public abstract class ApplicationEvent extends EventObject {
        . . . . . .
    **}
    

    七、实现(Realization)**
    实现(Realization)描述的是一个类实现了接口(可以是多个)。上面描述的弱是(weak is-a)关系就可以用接口表示。例如字符串是可以被序列化的,这就可以用实现来描述。

    public final class String  implements java.io.Serializable, Comparable<String>, CharSequence {
        . . . . . .
    }
    

    八、参考资料
    http://usna86-techbits.blogspot.com/2012/11/uml-class-diagram-relationships.html
    http://javarevisited.blogspot.com/2014/02/ifference-between-association-vs-composition-vs-aggregation.html

    展开全文
  • 针对物联网中数据实效性强的特点,结合物联网搜索中用户的高异构性和动态性,提出一种基于组合双向拍卖的搜索任务分配模型,从市场供求关系的角度描述了搜索发起者、搜索参与者和搜索引擎之间的关系。首先引入了竞价...
  • 介绍了关于JBT6644-2007滚动轴承滚针和双向推力圆柱滚子组合轴承的详细说明,提供其它知识的技术资料的下载。
  • 组合双向拍卖分析为基础,建立了相关的数学模型,分别对单一回合和多个回合的组合双向拍卖交易机制进行了研究,证明多回合组合双向拍卖能更大地提高社会福利,也为进一步...
  • 双向触发二极管的代换方法 双向触发二极管(2CTS)是属于三层结构,具有正、反向转折电压,且其正、反向伏安特性非常对称。常见型号有DB3型双向触发二极管,实测它的正反向击穿(可逆)电压为25V左右。附图2为简易...
  • 电信设备-双向移动组合式烟尘捕集罩.zip
  • 基于卷积神经网络与双向长短时记忆网络组合模型的短时交通流预测.pdf
  • 三孔双向卧式组合镗床夹具设计.zip机械设计毕业设计
  • 针对跨数据中心的资源调度问题,提出了一种基于组合双向拍卖(PCDA)的资源调度方案。首先,将云资源拍卖分为三个部分:云用户代理报价,云资源提供商要价,拍卖代理组织拍卖;其次,在定义用户的优先级及任务紧迫度...
  • 企业双向选择优化组合改革总结大会讲话.pdf
  • 以采用钢筋混凝土桥墩和...在此基础之上,考虑双向地震作用影响对弹塑性需求曲线进行折减,提出了预测组合刚构桥在任意方向输入的水平双向地震作用下位移响应的静力弹塑性分析方法,分析结果表明该方法有足够的保证率。
  • 考虑到组合双向拍卖与网格资源选择过程存在较高相似性,提出基于组合双向拍卖的网格资源管理方案,建立了具体的包含虚拟卖家的多回合组合双向拍卖机制。在该机制中,采用一种动态报价策略以提高拍卖交易率,同时通过引入...
  • 针对云计算环境下资源的特点以及运用经 济机制进行资源分配所具有的灵活性及有效性,本文提出了一种在云计算环境下基于双向拍卖的资源分配模型。首先,给出改进的周期性双向拍卖模型,采用分段拟 合的方法来确定买卖...
  • UWB模块SKU609 是一款蓝牙UWB组合模块,蓝牙方案采用NRF52832、UWB方案采用DW1000。可以广泛应用于UWB(TDOA、TWR)高精度定位系统,也可以应用于基于UWB的精准双向测距。内嵌加速传感器,可以实现静止和运动条件下...
  • 针对组合双向正激直流变换器型和直流斩波器型高频环节逆变器电路结构的不同.首次对这两种高频环节逆变器的控制策略、原理特性、关键电路参数设计准则等进行比较研究。采用理论推导方法,获得两种逆变器占空比、输出...
  • 行业资料-电子功用-双向调节风力发电机塔筒吊装专用组合吊具.zip
  • 电子政务-分体组合双向电缆卷盘.zip
  • 电子政务-两维双向轮机组合波力发电装置.zip
  • 电子政务-双向使用的充电电池组合结构.zip
  • 基于组合双向拍卖理论的云计算资源定价研究,薛辉,吴俊,随着云计算的不断发展,各大企业都开始提供云计算服务,云计算的市场规模在不断地扩大,云计算资源定价相关研究也越来越多,本文
  • 行业资料-电子功用-径向多线圈组合式高速双向电磁铁
  • 从通用服务质量、领域相关服务质量和业务的组合关联度3个方面考虑组合服务选取,充分保证了组合服务的质量,并将组合Web服务选取问题转化为最长路径选取问题,给出了一种双向动态规划的求解策略。
  • 基于多归属组合双向拍卖的SDN资源价格协商算法研究
  • 粗镗CKV型主轴箱Φ8852Φ685三孔双向卧式组合镗床毕业论文.doc
  • 行业分类-设备装置-双向翻盖式一次成型纸质包装盒和组合包装盒.zip
  • 哈希表+双向链表的组合使用

    千次阅读 2016-03-24 13:47:38
    首先看一下常用的hash表与双向链表结组合使用,这样的组合一般使用在网络通讯中,接收端收到大量的新数据消息, 将消息先存储到hash中,查询快捷,方便。 哈希表是由一个表头加上若干个节点组成,每个...

    在一个老牌通信公司工作几年,做的核心网项目开发,整天关注的是call flow,所参与的项目基本和MM和Call Control相关,

    大多重点在项目开发逻辑,以及信令的解析和分析上。

    公司内部代码有很多优秀的设计细节,和架构方式,只不过平时在此宏观的架构的基础上添加新代码,使用优秀简洁的接口,很少

    仔细分析这些代码的优势所在。其中包括网络通信,进程间通信,以及多线程,共享内存,进程管理,状态机,以及定时器,

    各种log机制。

    最近有了一些闲暇时间,准备细细阅读基础代码,将一些优秀的设计理念和方法,加以整理总结。


    首先看一下常用的hash表与双向链表结组合使用,这样的组合一般使用在网络通讯中,接收端收到大量的新数据消息,

    将消息先存储到hash中,查询快捷,方便。


    哈希表是由一个表头加上若干个节点组成,每个节点都是一个双向链表,数据对象实际是存储在哈希表节点的双向链表节点中。

    由于每个节点都是一个双向链表,链表的每个节点中存储数据。

    这样的好处是,如果随机产生的hash值如果相同,也可以使用,也不用重新产生命中的相同的hash值,可以直接存入对应的双向链表中。

    这需要一个很好的散列化的hash函数,将数据对象均匀分布到节点的链表中。


    哈希表的表头中定义了:

    1. 哈希表的节点的最大个数变量

    2. 产生哈希值的哈希函数指针变量的定义

    3. 用于查找的对比函数指针变量的定义

    4. 定义存储节点的数组

    5. 存储数据对象的个数

    双向链表定义:

    1. 带有双向指针的表头

    2. 带有双向指针的表尾

    3. 带有双向链表中存储数据的个数


    哈希表的表头定义如下:

    /**
     * data structure of hash table
     */
    typedef struct _HASHTABLE
    {
            /// static configurable data of hash table
            int             numBuckets;     /// number of bucket in this hash table
            HASHFUNCPTR     hashFunc;       /// hash function from key to bucket
            COMPFUNCPTR     cmpFunc;        /// comparison function to the key of the object
            DLIST_P         bucketArray;    /// array of buckets in this hash table
    
            /// dynamic data of hash table
            int             numObjects;     /// number of objects in this hash table
    } HASHTABLE_T, *HASHTABLE_P;


    双向链表的定义如下:

    /**
     *
     * The double linked list is used to manage the list of objects for specific purpose.
     * It allows the user to insert the object into or remove it from the list dynamically.
     *
     * To link them together, the object MUST contain GEN_NODE_T as the first element in its
     * structure, so that we can cast the pointer to the object to the GEN_NODE_P. 
     *
     * The structure of double linked list looks like the following.
     *
     *		+----------+         +----------+                         +----------+
     *     NULL <---+-- prev   |<--------+-- prev   |<--------       <--------+-- prev   |
     *		+----------+         +----------+           ...           +----------+
     *		|   next --+-------->|   next --+-------->       -------->|   next --+--->NULL
     *		+----------+         +----------+                         +----------+
     *		|   data   |         |   data   |                         |   data   |
     *		+----------+         +----------+                         +----------+
     *		     ^                                                         ^
     *        	     |                                                         |
     *   		     |                                                         |       
     *  		 head(list)                                                tail(list)    
     *
     */
    
    /**
     * data structure of double linked list
     */
    typedef struct _DLIST
    {
    	/// dynamic data of this list
    	GEN_NODE_P	head;		/// pointer to the head node of this list
    	GEN_NODE_P	tail;		/// pointer to the tail node of this list
    	int		numObjects;	/// current number of nodes in this list
    } DLIST_T, *DLIST_P;

    /**
     * data structure of general purpose node used in double linked list
     *
     */
    typedef struct _GEN_NODE {
            struct _GEN_NODE        *prev;          /// pointer to the previous node in the list
            struct _GEN_NODE        *next;          /// pointer to the next node in the list
    } GEN_NODE_T, *GEN_NODE_P;
    



    哈希表的创建:创建函数中有带入两个函数指针类型的函数,一个是hash函数,一个是对比函数,在头文件中事先定义好对应的函数指针。

    哈希函数指针的定义

    typedef unsigned int    (* HASHFUNCPTR)(const void *key);
    对比函数指针的定义
    typedef int     (* COMPFUNCPTR)(const void * obj, const void *key);
    

    HASHTABLE_P HashTable_create(int numBuckets, HASHFUNCPTR hashFunc, COMPFUNCPTR cmpFunc)
    {
            HASHTABLE_P ht = NULL;
    
            assert((hashFunc != NULL) && (cmpFunc != NULL) && (numBuckets > 0));
    
            ht = (HASHTABLE_P)calloc(1, sizeof(HASHTABLE_T) + sizeof(DLIST_T) * numBuckets);
    
            if (ht != NULL) {
                    ht->numBuckets = numBuckets;
                    ht->hashFunc = hashFunc;
                    ht->cmpFunc = cmpFunc;
                    ht->bucketArray = (DLIST_P)(ht + 1);
            }
    
            return ht;
    }

    这个函数是创建整个哈希表,为哈希表申请内存空间,包括哈希表的表头,还同时创建了numBuckets个双向链表。

    在此用的申请空间的函数是calloc,在申请完空间后,会自动将空间清空。这是一个好的使用方法。

    将哈希函数和对比函数的函数指针,赋入函数。

    具体使用方法如下:

    /* Max Number of Active CSFB CALL in Queue */
    #define MAX_CSFB_CALL           4096

            g_pPgrHash  = HashTable_create(MAX_CSFB_CALL, s102PgrHash, s102PgrCmp);</span>
            if (g_pPgrHash  == NULL)
            {
                    UX_ID_ELOG(ES1020623, "Unable to HashTable_create g_pPgrHash \n");
                    UXTPCU(A21_KILL_SIG);
            }
    



    销毁整个哈希表:销毁整个hash表,可以先调用清空此哈希表中所有数据的值,然后将申请的hash表的内存空间free掉。

    void HashTable_destroy(HASHTABLE_P ht, FREEFUNCPTR freeFunc)
    {
            assert(ht != NULL);
    
            // delete all the object from each bucket
            HashTable_delAllObjs(ht, freeFunc);
    
            // release the memory for hashtable
            free(ht);
    
            return;
    }
    



    哈希表插入数据:

    可以根据查找函数HashTable_getBucket(),此函数的功能是根据key值,调用hash函数,产生hash值,返回对应数组中双向链表的地址。

    然后调用双向链表的插入函数,将数据加入到双向链表的表尾处。

    int HashTable_addObj(HASHTABLE_P ht, void *key, void *obj)
    {
            DLIST_P bucket = NULL;
    
            assert((ht != NULL) && (key != NULL) && (obj != NULL));
    
            bucket = HashTable_getBucket(ht, key);
            if (bucket == NULL) return HASHTABLE_ERROR_HASHFAIL;
    
            if (DList_addObjTail(bucket, obj) != DLIST_NO_ERROR) {
                    return HASHTABLE_ERROR_INSERTFAIL;
            }
    
            ht->numObjects++;
            return HASHTABLE_NO_ERROR;
    }
    


    双向链表添加数据的函数如下:

    int DList_addObjTail(DLIST_P list, void *obj)
    {
            assert((list != NULL) && (obj != NULL));
    
            GEN_NODE_P node = (GEN_NODE_P)obj;
            node->prev = list->tail;
            node->next = NULL;
    
            if (list->tail == NULL) {
                    if ((list->head != NULL) || (list->numObjects != 0)) {
                            return DLIST_ERROR_INCONSISTENT;
                    }
    
                    list->head = node;
            } else {
                    node->prev->next = node;
            }
    
            list->tail = node;
            list->numObjects++;
    
            return DLIST_NO_ERROR;
    }

    OBJ即为插入的数据对象,此数据对象有个要求,此数据结构的第一个变量必须是GEN_NODE_T      link;   

    双向链表可以从head往里插入数据,也可从tail处插入数据。

    此次是从tail处插入数据。

    1. 首先将数据对象的首地址强制转换成节点类型,这就是为什么数据对象的结构体的第一个变量为什么必须是GEN_NODE_T 类型的缘故,将数据前后链接。

    2. 从结尾处插入数据,将此节点的前驱指向双向链表的tail,将此节点的后继设为空。

    3. 由于是双向链表,前一个数据,需要将后继改为新加入的节点,如果此链表为空,可直接将链表的头指向此数据对象节点。

    4.从结尾出插入数据,新加入的数据即为tail,将链表的tail指向新加入的数据节点

    5. 将链表中数据对象的个数加1


    使用方法如下:

                           // add this csr into hash table with given key
                            retVal = HashTable_addObj(g_pCsrHash, (void *)mnidPtr, (void *)&g_s102csr[objId]);
    
                            if (retVal != HASHTABLE_NO_ERROR) {
                                    UX_ID_ELOG( ES1020576, "Failed to call HashTable_addObj to add the csr index %d : retval: %d", objI\
    d, retVal);
                                    /// free the Correlation Id for other request message
                                    Allocator_freeObject(g_pCsrIdleList, objId);
                                    index = -1;
                            }


    哈希表查找数据:

    void *HashTable_findObj(HASHTABLE_P ht, void *key, DLIST_P *bucket)
    {
            DLIST_P bkt = NULL;
            void    *obj = NULL;
    
            assert((ht != NULL) && (key != NULL));
    
            bkt = HashTable_getBucket(ht, key);
            if (bkt != NULL) {
                    obj = DList_findObj(bkt, ht->cmpFunc, key);
            }
    
            if (bucket != NULL) *bucket = bkt;
    
            return obj;
    }
    

    根据查找函数HashTable_getBucket 获取key值应该放得节点位置

    根据key值,调用hash函数,产生hash值,返回对应数组中双向链表的地址。

    根据对比key,在此双向链表中查询此对象key值,如果找到,返回对应节点的地址。

    根据节点地址,可获取此节点中对象的数据。

    从双向链表中查找数据的函数如下:

    void* DList_findObj(DLIST_P list, COMPFUNCPTR cmpFunc, void *key)
    {
            assert((list != NULL) && (cmpFunc != NULL) && (key != NULL));
    
            GEN_NODE_P      node = list->head;
            int             count = 0;
    
            while ((node != NULL) && (count < list->numObjects)) {
                    if ((* cmpFunc)((void *)node, key) == 0) return (void *)node;
                    count++;
                    node = node->next;
            }
    
            return NULL;
    }
    通过对比函数将key值和链表中的数据key值进行对比,返回节点地址。


    哈希表删除一条数据:

    void *HashTable_removeObj(HASHTABLE_P ht, void *key)
    {
            DLIST_P bucket = NULL;
            void    *obj = NULL;
    
            assert((ht != NULL) && (key != NULL));
    
            obj = HashTable_findObj(ht, key, &bucket);
    
            if (obj != NULL) {
                    if (bucket != NULL) {
                            DList_removeObj(bucket, obj);
                            ht->numObjects--;
                    } else {
                            return NULL;
                    }
            }
    
            return obj;
    }
    

    在此哈希表中删除一条数据包含了哈希表查找数据,然后再双向链表中将此数据删除,hash表中数据总个数减1。


    双向链表删除一个对象的函数如下:

    void DList_removeObj(DLIST_P list, void *obj)
    {
            assert(list != NULL);
    
            GEN_NODE_P node = (GEN_NODE_P)obj;
    
            if (node == NULL) return;
    
            if (node->prev == NULL) {
                    // if the object is the head of list, set the head to the next object
                    list->head = node->next;
            } else {
                    // otherwise, let the previous one links to the next object
                    node->prev->next = node->next;
            }
    
            if (node->next == NULL) {
                    // if the object is the tail of list, set the tail to the previous object
                    list->tail = node->prev;
            } else {
                    // otherwise, let the next one links to the previous object
                    node->next->prev = node->prev;
            }
    
            // clear the linkage of this object
            node->prev = NULL;
            node->next = NULL;
    
            list->numObjects--;
            return;
    }
    

    删除一个对象的流程如下:

    1. 首先将数据对象的首地址强制转换成节点类型,这就是为什么数据对象的结构体的第一个变量为什么必须是GEN_NODE_T 类型的缘故,将数据前后链接,便于操作。

    2. 如果要删除的节点的前驱是空,表明此节点为head,将此节点的后继设为head即可

    3. 如果要删除的节点的前驱不是空,将此节点前驱的后继指向此节点的后继。

    4. 如果要删除的节点的后继是空,表明此节点为tail,将此节点的前驱设为tail即可

    5.  如果要删除的节点的后继不是空,将此节点后继的前驱设为此节点的前驱

    6. 将此节点前驱后继,设为null

    7.链表中的数据总个数减1


    清空整个哈希表:

    void HashTable_delAllObjs(HASHTABLE_P ht, FREEFUNCPTR freeFunc)
    {
            int i;
    
            assert(ht != NULL);
    
            for (i=0; i<ht->numBuckets; i++) {
                    DList_delAllObjs(&ht->bucketArray[i], freeFunc);
            }
    
            ht->numObjects = 0;
    
            return;
    }
    

    获取哈希表中存储数据对象的个数:

    int HashTable_getSize(HASHTABLE_P ht)
    {
            assert(ht);
    
            if (ht->numObjects < 0) return HASHTABLE_ERROR_INCONSISTENT;
            return ht->numObjects;
    }
    

    根据key值获取哈希表数据节点的位置:

    DLIST_P HashTable_getBucket(HASHTABLE_P ht, void *key)
    {
            int slot = 0;
    
            assert((ht != NULL) && (key != NULL));
    
            slot = (* ht->hashFunc)(key);
            if ((slot < 0) || (slot >= ht->numBuckets)) return NULL;
    
            return &ht->bucketArray[slot];
    }
    

    根据key值,调用hash函数,产生hash值,返回对应数组中双向链表的地址。


    以上为hash表的操作中套用双向链表的操作方法。

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 95,202
精华内容 38,080
关键字:

双向组合