• 关于

    树形类

    的搜索结果

问题

利用内存多叉树实现Ext JS中的无限级树形菜单(一种构建多级有序树形结构JSO?400报错

利用内存多叉树实现Ext JS中的无限级树形菜单(一种构建多级有序树形结构JSON的方法)? 400 报错 利用内存多叉树实现Ext JS中的无限级树形菜单(一种构建多级有序树形结构JSON的方法) 一、问题...
爱吃鱼的程序员 2020-05-31 00:31:27 0 浏览量 回答数 1

问题

jsp页面布局,首页左侧是一个树形菜单路径都是访问后台返回jsp页面,怎么使点击菜单后,首页右侧显示类容

大神求拯救...
a123456678 2019-12-01 20:22:34 1046 浏览量 回答数 1

回答

基本术语: 假设记录集大小为n。排序过程需要经过若干趟操作,每一趟操作由若干次子操作组成。 算法思想: 选择类排序(包括简单选择排序、树形选择排序和堆排序等)的基本算法思想是执行第i趟操作时,从第i条记录后选择一条最小的记录和第i条记录交换。 初始状态: 49 38 65 97 76 13 27 第一趟: 从(38 65 97 76 13 27)中选择最小值13与49交换 13 38 65 97 76 49 27 第二趟: 从(65 97 76 49 27)中选择最小值27与38交换 13 27 65 97 76 49 38 ... ...
青衫无名 2019-12-02 01:18:06 0 浏览量 回答数 0

回答

不记得有代替in的语句,可能也是因为我不太关注sql导致水平较低哈。这种问题通常是由于无限分类表本身的设计问题导致的,例如只有id, parent_id两个字段,所以只要in了,如果无限分类表包含 id, parent_id, level(树高), path这个字段的时候就可以避免使用in了。我个人使用的一个无限分级表包括以下的字段id 唯一索引parent_id 父级的idnumber 数轴投影序号leve 树高left_number 已当前节点为树根时,其下的最左端的子节点的数轴投影序号一个简单的例子演变:[id:1, level:1 number: 1, left_number:1]插入一个子节点[id:1, level:1 number: 2, left_number:1][id:2, level:2 number: 1, left_number:1]于level2再插入一个子节点[id:1, level:1 number: 3, left_number:1][id:2, level:2 number: 1, left_number:1] [id:2, level:2 number: 2, left_number:2]这种树形的数据维护很麻烦,但是搜索要快的多,例如任意节点下的全部子节点就是left_number到number-1。用这个做过一个Chuan啊销系统的人员结构树,效果很不错。核心思路就是把一颗树的分支转换为数轴上的点/线段,从而在数轴上得到完整的树的投影。忘了一个top_id,表示节点对应的根节点,否则表里面有多颗树的话就出问题了。
a123456678 2019-12-02 03:03:19 0 浏览量 回答数 0

回答

目前为止,在一个对象上实现迭代最简单的方式是使用一个生成器函数。 在4.2小节中,使用Node类来表示树形数据结构。你可能想实现一个以深度优先方式遍历树形节点的生成器。 下面是代码示例: class Node: def __init__(self, value): self._value = value self._children = [] def __repr__(self): return 'Node({!r})'.format(self._value) def add_child(self, node): self._children.append(node) def __iter__(self): return iter(self._children) def depth_first(self): yield self for c in self: yield from c.depth_first() # Example if __name__ == '__main__': root = Node(0) child1 = Node(1) child2 = Node(2) root.add_child(child1) root.add_child(child2) child1.add_child(Node(3)) child1.add_child(Node(4)) child2.add_child(Node(5)) for ch in root.depth_first(): print(ch) # Outputs Node(0), Node(1), Node(3), Node(4), Node(2), Node(5) 在这段代码中,depth_first() 方法简单直观。 它首先返回自己本身并迭代每一个子节点并 通过调用子节点的 depth_first() 方法(使用 yield from 语句)返回对应元素。
哦哦喔 2020-04-16 21:29:15 0 浏览量 回答数 0

回答

在线文档在线文档是知识库主要的知识载体。你可以把它理解成可多人协作的在线Word文档;它还具有高度结构化、富有关联性的特点(符合知识网状的结构),能够承载更加丰富的动态内容。在线文档通过树形目录组织,每一个文档都可以在它的子级创建新的文档。文件除了在知识库中创建在线文档,你可以直接上传既有的文件类型的知识内容。目前我们支持上传Office、PDF、TXT这些文本类文件,并支持直接预览。文件夹文件夹是一个用于分组,其中可以包含子文件夹、在线文档和文件。
爱吃鱼的程序员 2020-12-28 10:31:30 0 浏览量 回答数 0

回答

经过我仔细的调试,发现使用配置对象之间的关联关系(@OneToMany )得到的关联对象并不会放到二级缓存中。例如上述例子中,我遍历整棵树,在递归得到孩子菜单时是通过Menu类的getChildren()方法,调用此方法得到的孩子菜单对象hibernate并不会放到二级缓存中。因此,为了使用上缓存,我自己写了另外一个方法findMyChildren(),代码如下: @SuppressWarnings("unchecked") public HashSet<Menu> findMyChildren(Menu m) { DetachedCriteria dc = DetachedCriteria.forClass(Menu.class); dc.add(Restrictions.eq("pid", m.getId())); List<Menu> menus = hibernateTemplateUseCache.findByCriteria(dc); HashSet<Menu> menusSet = new HashSet<Menu>(menus); return menusSet; } 然后递归取得孩子菜单时使用此方法,此方法返回的孩子菜单都会被保存到二级缓存中,以后访问时会直接从缓存中拿。由于项目的菜单在程序运行过程中不会被修改,因此只需从数据库加载一次。于是修改EhCache配置: <cache name="Menu" maxElementsInMemory="200" eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> 这样一来,就达到了树形结构数据永远去缓存中取的目的。
爵霸 2019-12-02 01:57:12 0 浏览量 回答数 0

回答

商品分类可以参考主流电商平台的设计,比如淘宝、京东之类的,简单点可以是树形结构,如: 女装 上衣 T恤 衬衫 ... 裤子 休闲裤 打底裤 短裤 ... 裙装 A字裙 连衣裙 ... 这种结构相对较为简单,本质上为一对多的关系,单表即可表示,通过父ID建立上下级关联,做Redis缓存设计时,可以简单的使用SET集合来实现 category:女装 => <上衣,裤子,裙装,...>category:女装:上衣 => ...如果是多对多结构的,如:T恤可属于上衣分类,也可属于夏装分类,此类结构,可以在分类表外多建一张关系表,用于表示多对多的关系,分类元数据仍然可以只使用一张表表示,不需要父ID字段,但在做Redis缓存设计时,稍微麻烦一点 父级与子级结构(SET) category:上衣 => category:夏装 => 子级与父级结构(SET) category:T恤:parents => <上衣,夏装>category:衬衫:parents => <上衣,夏装>使用上述结构的原因是,维护缓存时,节点的变更会同时影响到上下级,所以上级对下级、下级对上级的关系都应有所表示,便于维护。假如上述案例中,要删除T恤分类,就需要根据T恤分类找到所有父类,再将父类下的T恤节点移除,如果需要删除夏装分类,则反回来需要查出所有夏装子节点,具体是要移除子结点还是其它处理逻辑则应根据业务需要来定。
爵霸 2019-12-02 02:00:21 0 浏览量 回答数 0

回答

该问题通常会抛出 NoSuchMethodError/ClassNotFoundException/IncompatibleClassChangeError 等异常,要解决此类问题: 1. 首先需要根据异常类定位依赖库,然后可以在项目中执行 mvn dependency:tree 以树形结构展示全部依赖链,再从中定位冲突的依赖库,也可 以增加参数 -Dincludes 指定要显示的包,格式为 [groupId]:[artifactId]:[- type]:[version],支持匹配,多个用逗号分隔,例如:mvn dependency:tree -Dincludes=power,javaassist; 2. 定位冲突包后就要考虑如何排包,简单的方案是用 exclusion 来排除掉其 从他依赖项目中传递过来的依赖,不过有的应用场景需要多版本共存,不同 组件依赖不同版本,就要考虑用 Maven Shade 插件来解决,详情请参考 Maven Shade Plugin。
Lee_tianbai 2020-12-30 13:28:29 0 浏览量 回答数 0

回答

一般情况下,建议采用商品和活动分表记录,然后通过一张关系表来建立联系,这样不管从商品找活动还是从活动找商品都会比较方便。对于近期活动需要快速读取的情况,甚至可以针对活动单独建立缓存数据,以提高读取效率。商品,活动,限购都是需要记录的事实。关键问题是“限购”应该怎样表示。由于限购本身还可能包含其他属性,比如限购日期等等,所以不是单单一个关联表(多对多关系)就能解决的。有两种方法可以记录限购:1)记录不限购的商品、活动2)记录限购的商品活动如果限购的商品活动数量相对较小,方法2)更合适。Product (ProductId, ...)Activity (ActivityId, ...)PurchaseRestriction (ProductId, ActivityId, StartDate, EndDate,...)你的疑问:这张映射表,属于哪个模块去维护商品、活动不是相互独立的,PurchaseRestriction 恰恰表示了它们之间的联系。PurchaseRestriction 既跟Product相关,又跟Activity相关。不是简单的“谁的属性”。很多人设计class时使用循环引用,比如,Product 拥有 RestrictedActivities 集合,Activity 拥有 RestrictedProducts 集合。你心里也有类似的疑问,一方面觉得限购是一个事实,只应该放在一个地方;另一方面,感觉限购既是Product的属性,又是Activity的属性。我觉得,这是面向对象的一个缺点,“对象拥有属性,属性必须属于某个对象”这个思想的根源是认为所有东西都是树状结构的。这跟树形数据库犯了同样的错误,后来出现网络数据库。网络数据库可以表达复杂的结构,但是过于复杂。关系数据库的出现,解决了树形数据库和网络数据库的问题。关系数据库是基于集合论和一阶谓词逻辑的模型,可以完美地表达各种结构。"模块化"当然很好,合理的模块化减少了程序各模块之间的耦合。但是,一个系统最大的耦合往往是程序和数据的耦合。数据的结构变了,程序必须跟着变。因此,规范的数据库设计比应用程序的模块化更重要。你把商品和活动分到不同的模块,一方面提高了抽象级别,模块化,另一方面割裂了它们的联系。虽然模块多了,但模块间的交互更复杂了。你的问题没有完美的答案,有3个解决方案:a) 商品模块去维护b) 活动模块去维护c) 单独的模块去维护。上面提到的(商品是否能参加活动,商品限购属性),我觉得第一个是可以归为商品固有属性,第二个可能通过一张映射表来记录(因为限购商品毕竟是少数)"商品是否能参加活动"可以由PurchaseRestriction推导出,不需要这样的属性。在程序里,也许有某个类,它有一个属性 CanTakePartInActivity. 但是数据库不能这样设计。
蛮大人123 2019-12-02 02:03:45 0 浏览量 回答数 0

回答

左上角要有LOGO,最好是异体汉字做成圆形,参考清华大学的校徽,不要放图片,要用SVG或者CSS3特效实现。上面要有大标题栏,最好有艺术字,波浪状带阴影的那种,参考中小学Photoshop大赛作品,要用CSS实现。要有访问计数器每次刷新会+1那种。左边要有网站功能树,Blog的话可以做成文章分类树,样式参考Windows资源管理器,展开和收起要有不同的效果。链接要用蓝色,鼠标指向时要有下划线,指针变成手形。重点链接前要有红色的Hot标签,新增内容前要有New标签,会动的更好,用transition或者animate实现。精采内容要有彩虹色的背景,可以用linear-gradient实现。二级页内要有向左的箭头图标,点击返回;还要有房子图标,点击回主页。页面底部要写版权所有,翻版必究,要加一个会转的地球,不要用Gif,用CSS Sprite技术或者Canvas技术实现。地球旁边可以加上W3C校验通过的图标,下面可以写上建议使用1024x768以上分辨率Internet Explorer 9以上浏览器查看。最好有一个小财神的形象在页面上跟着鼠标移动,鼠标移动时它会有加速跟上的过程。
西秦说云 2019-12-02 02:36:56 0 浏览量 回答数 0

回答

这样表就多了,我觉得可以这样,有一个字段seq,记录层级关系,形如 .一级id.二级id.三级. ,查询比较方便###### 引用来自“withlogic”的评论这样表就多了,我觉得可以这样,有一个字段seq,记录层级关系,形如 .一级id.二级id.三级. ,查询比较方便 表是多了,不过并不会影响查询吧? 需要的查询大概是这么几种: 1、查询本身 根据名字查询:这个最基本的要求貌似比较复杂,那就再搞一个表?可是这样就不符合我的本意了。 查询父分类、查询子分类:一个where就行了 查询上一层所有分类、查询下一层所有分类:那不有第几级么,也是一个where,不过好像会有N多个嵌套查询 难道真的要用树? 或者有多少级分类就动态创建多少个表? ###### 引用来自“withlogic”的评论这样表就多了,我觉得可以这样,有一个字段seq,记录层级关系,形如 .一级id.二级id.三级. ,查询比较方便 嗯,想了想,可以有多少级分类,就创建几个表,这样表不会太多,查询复杂度也降低了。 就是这个spring+hibernate怎样实现是个问题。能给点建议不?或者给个实际可运行的例子也是可以的 ###### 用一张表就可以了,字段有id,name,famliy(家族链,是它上级所有id,包括自已的id,用特珠殊符合连在一起,如“,”,这样可以放便查询这个类上面所有的上级),level(级别,在整个家族的层级,可以根据这个查同级的类别),parent_id(上级ID,一般异步查询是用到),就目前这张表还是比较适用的。 ######同意这种,比左右值方法更新的简单,比简单粗暴的上下级查询效率好(虽然我大多数情况用这种)######最好不要太多表,你是要怎么样实现?你自己逻辑都说了 不难啊
kun坤 2020-06-14 10:48:23 0 浏览量 回答数 0

问题

使用 ASM 实现 Java 语言的“多重继承”:报错

简介: 尽管大部分情况下我们并不需要多重继承,但总有一些情况下我们不得不做出多重继承的考虑。但又由于 Java 语言本身不支持多重继承,这就会带来问题。本文试图使用 ASM 来解决这一问题。 ...
kun坤 2020-06-06 15:29:41 0 浏览量 回答数 1

问题

搜索引擎背后的经典数据结构和算法 6月10日 【今日算法】

前言 我们每天都在用 Google, 百度这些搜索引擎,那大家有没想过搜索引擎是如何实现的呢,看似简单的搜索其实技术细节非常复杂,说搜索引擎是 IT 皇冠上的明珠也不为过,今天我们来...
游客ih62co2qqq5ww 2020-06-15 07:32:11 0 浏览量 回答数 0

问题

【Android】树形菜单、扩展下拉菜单BaseExpandableListAdapte..:报错

先看效果~     也就是BaseExpandableListAdapter、AbsListView类的使用,就不多说了..大牛留情...   就两个类。 ExpandLabel: package com.y...
kun坤 2020-06-20 11:23:59 0 浏览量 回答数 1

问题

【阿里云】学习linux推荐鸟哥私房菜基础篇【内置教程】

linux常用命令大全: arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS / ...
自娱自乐 2019-12-01 21:47:16 10722 浏览量 回答数 4

回答

Collection 总接口 --| List 特征 有序 可重复 ----| ArrayList 底层维护的是一个Object类型的数组,如果使用无参构造方法创建ArrayList集合,默认的容量为10 ​ 用带有参数的构造方法,创建ArrayList集合,传入的initCapacity是多少,容量就是多少 ​ 特征: 增删慢 查找快 ​ newCapacity = oldCapacity + (oldCapacity >> 1) 二进制位运算 ----| LinkedList 底层维护的是一个双向链表 特征是增删快 查找慢 ----| Vector 线程安全的ArrayList 和ArrayList基本相同,JDK1.0的古老产物。效率低于ArrayList --| Set 特征 无序 不可重复 ----| HashSet 底层维护是一个哈希表,存储效率极高 ​ 一个自定义类对象放入到HashSet中,需要经历如下过程: ​ 通过当前类对象的HashCode,获取到当前类对象的哈希值,进行移位运算,计算出当前元素应该保存到哈希表中的位置。 ​ 情况1: 当前位置没有元素,直接放入 ​ 情况2: 当前位置已经存在其他元素。需要调用该元素的equals方法,进行比较,如果比较结果为两个元素不同,能够放入,两个元素相同,不能放入。 ----| TreeSet 树形结构的Set集合 ​ 能够放入TreeSet中的元素必须有自然顺序,或者提供【比较规则】 ​ 一个自定义类对象,想要放入到TreeSet集合中,有两种方式 ​ 1. 当前类【遵从】Comparable接口,实现compareTo(Object o)方法 ​ 2. 实现一个自定义的比较器【遵从】Comparator接口,实现compare(Object o1, Object o2)方法 Collection中的方法 //添加方法: add(Object o) //添加指定元素 addAll(Collection c) //添加指定集合 //删除方法: remove(Object o) //删除指定元素 removeAll(Collection c) //输出两个集合的交集 retainAll(Collection c) //保留两个集合的交集 clear() //清空集合 //查询方法: size() //集合中的有效元素个数 toArray() //将集合中的元素转换成Object类型数组 //判断方法: isEmpty() //判断是否为空 equals(Object o) //判断是否与指定元素相同 contains(Object o) //判断是否包含指定元素 containsAll(Collection c) //判断是否包含指定集合 List中的方法 //添加方法: add(int index, Object o) //向指定位置添加元素 addAll(int index, Collection c) //向指定位置添加集合 //删除方法 remove(int index) //删除指定元素 //查询方法: get(int index) //获取指定位置的元素 indexOf(Object o) //获取指定元素的位置 lastIndexOf(Object o) //获取指定元素最后一次出现的位置 //修改方法: subList(int fromIndex, int toIndex) //截取子集合从fromIndex到toIndex,要头不要尾 set(int index, Object o) //修改指定位置的元素 ArrayList中特有的方法 ensureCapacity(int minCapactiy) //判断当前数组中的元素个数是否大于指定的minCapacity trimToSize() //修改数组容量为当前数组有效元素个数 LinkedList中特有的方法 //查询方法: getFirst() //获取集合中的第一个元素 getLast() //获取集合中的最后一个元素 //添加方法: addFirst(Object o) //在集合的第一个位置添加指定元素 addLast(Object o) //在集合的最后一个位置添加指定元素 //删除方法: removeFirst() //删除集合中的第一个元素 removeLast() //删除集合中的最后一个元素 Collection中的迭代器Iterator方法 Iterator iterator(); //迭代器构造方法 boolean hasNext() //判断是否有下一个元素 Object next() //获取当前元素 void remove() //删除通过next()获取的元素,在next()之后使用,不可以单独使用 List中的迭代器 ListIterator方法 ListIterator listIterator(); //迭代器构造函数 boolean hasNext() //判断是否有下一个元素 boolean hasPrevious() //判断是否有上一个元素 Object next() //获取当前元素 Object previous() //获取上一个元素 void remove() //删除通过next()获取的元素,在next()之后使用,不可以单独使用 add(Object o) //添加指定元素 set(Object o) //修改指定元素 int nextIndex() //获取当前元素所在位置
景凌凯 2020-04-07 17:20:03 0 浏览量 回答数 0

问题

【精品问答】110+数据挖掘面试题集合

数据挖掘工程师面试宝典双手呈上,快来收藏吧! 1.异常值是指什么?请列举1种识别连续型变量异常值的方法? 2.什么是聚类分析? 3.聚类算法有哪几种?选择一种详细描述其计算原理和步骤。 4.根据要求写出SQL ...
珍宝珠 2019-12-01 21:56:45 2713 浏览量 回答数 3

问题

关于商品无限级分类的数据库设计[ORM框架为Hibernate]:报错

小弟最近在做一个在线书店系统,在做分类的时候想要设计的尽可能的具有通用性,也就是说可以适应大多数场景的分类需求。 我查到的分类表设计方案大概是这么几种:[http://www.cnblogs....
kun坤 2020-06-14 10:48:17 0 浏览量 回答数 1

问题

关于集成测试你了解多少?

       集成测试,也叫组装测试或联合测试。在单元测试的基础上,将所有模块按照设计要求(如概要设计文档)集成为子系统或系统,是单元测试的逻辑扩展。最简单的形式是:两个已经测试过的单...
技术小菜鸟 2019-12-01 21:34:34 3904 浏览量 回答数 1

问题

Java 处理 XML 的三种主流技术及介绍:报错

 XML (eXtensible Markup Language) 意为可扩展标记语言,它已经是软件开发行业中大多数程序员和厂商用以选择作为数据传输的载体。本文作者对于 Java 处理 XML 的几种主流技术进行一些总结和介绍...
kun坤 2020-06-09 23:26:43 0 浏览量 回答数 1

问题

【精品问答】python技术1000问(2)

为了方便python开发者快速找到相关技术问题和答案,开发者社区策划了python技术1000问内容,包含最基础的如何学python、实践中遇到的技术问题、python面试等维度内容。 我们会以每天至少50条的...
问问小秘 2019-12-01 22:03:02 3129 浏览量 回答数 1

回答

考试内容一、基础知识1.计算机系统的组成和应用领域。2.计算机软件的基础知识。3.计算机网络的基础知识和应用知识。4.信息安全的基本概念。二、数据结构与算法1.数据结构、算法的基本概念。2.线性表的定义、存储和运算。3.树形结构的定义、存储和运算。4.排序的基本概念和排序方法。5.检索的基本概念和检索算法。三、操作系统1.操作系统的基本概念、主要功能和分类。2.进程、线程、进程间的通信的基本概念。3.存储管理、文件管理、设备管理的主要技术。4.典型操作系统的应用。四、数据库系统的基本原理1.数据库的基本概念,数据库系统的组成。2.数据模型概念和主要的数据模型。3.关系数据模型的基本概念,关系操作和关系代数。4.结构化查询语言SQL。5.事务管理、并发控制、故障恢复的基本概念。五、数据库设计和数据库应用1.关系数据库的规范化理论。2.数据库设计的目标、内容和方法。3.数据库应用开发工具。4.数据库技术发展。六、上机操作1.掌握计算机基本操作。2.掌握C语言程序设计基本技术、编程和调试。3.掌握与考试内容相关的知识的上机应用。其实三级数据库广度挺大,没什么深度,就算有几项知识不熟悉也没关系,但像C语言这样的基础知识应该打好一点,市场上的同类书都差不多,没什么特别的,你如果有时间可以买一本回来仔细看,我觉得只要真正仔细看了,肯定能过的(我以前就是没仔细看书,结果考的时候发现很多题目似曾相识,好后悔啊……),时间不是很多的话建议多做以前的题目,重复的几率很高,而且你想,总共就那么些个知识,又不能出太深,出不了什么新题的,考过的都知道,大差不离。
沉默术士 2019-12-02 01:23:55 0 浏览量 回答数 0

回答

触及 multiple inheritance (MI)(多继承)的时候,C++ 社区就会鲜明地分裂为两个基本的阵营。一个阵营认为如果 single inheritance (SI)(单继承)是有好处的,multiple inheritance(多继承)一定更有好处。另一个阵营认为 single inheritance(单继承)有好处,但是多继承引起的麻烦使它得不偿失。在本文中,我们的主要目的是理解在 MI 问题上的这两种看法。   首要的事情之一是要承认当将 MI 引入设计领域时,就有可能从多于一个的 base class(基类)中继承相同的名字(例如,函数,typedef,等等)。这就为歧义性提供了新的时机。例如: class BorrowableItem { // something a library lets you borrowpublic: void checkOut(); // check the item out from the library ..}; class ElectronicGadget {private: bool checkOut() const; // perform self-test, return whether ... // test succeeds}; class MP3Player: // note MI herepublic BorrowableItem, // (some libraries loan MP3 players)public ElectronicGadget{ ... }; // class definition is unimportant MP3Player mp; mp.checkOut(); // ambiguous! which checkOut?    注意这个例子,即使两个函数中只有一个是可访问的,对 checkOut 的调用也是有歧义的。(checkOut 在 BorrowableItem 中是 public(公有)的,但在 ElectronicGadget 中是 private(私有)的。)这与 C++ 解析 overloaded functions(重载函数)调用的规则是一致的:在看到一个函数的是否可访问之前,C++ 首先确定与调用匹配最好的那个函数。只有在确定了 best-match function(最佳匹配函数)之后,才检查可访问性。这目前的情况下,两个 checkOuts 具有相同的匹配程度,所以就不存在最佳匹配。因此永远也不会检查到 ElectronicGadget::checkOut 的可访问性。   为了消除歧义性,你必须指定哪一个 base class(基类)的函数被调用: mp.BorrowableItem::checkOut(); // ah, that checkOut...   当然,你也可以尝试显式调用 ElectronicGadget::checkOut,但这样做会有一个 "you're trying to call a private member function"(你试图调用一个私有成员函数)错误代替歧义性错误。    multiple inheritance(多继承)仅仅意味着从多于一个的 base class(基类)继承,但是在还有 higher-level base classes(更高层次基类)的 hierarchies(继承体系)中出现 MI 也并不罕见。这会导致有时被称为 "deadly MI diamond"(致命的多继承菱形)的后果。 class File { ... };class InputFile: public File { ... };class OutputFile: public File { ... };class IOFile: public InputFile,public OutputFile{ ... };    在一个“在一个 base class(基类)和一个 derived class(派生类)之间有多于一条路径的 inheritance hierarchy(继承体系)”(就像上面在 File 和 IOFile 之间,有通过 InputFile 和 OutputFile 的两条路径)的任何时候,你都必须面对是否需要为每一条路径复制 base class(基类)中的 data members(数据成员)的问题。例如,假设 File class 有一个 data members(数据成员)fileName。IOFile 中应该有这个 field(字段)的多少个拷贝呢?一方面,它从它的每一个 base classes(基类)继承一个拷贝,这就暗示 IOFile 应该有两个 fileName data members(数据成员)。另一方面,简单的逻辑告诉我们一个 IOFile object(对象)应该仅有一个 file name(文件名),所以通过它的两个 base classes(基类)继承来的 fileName field(字段)不应该被复制。   C++ 在这个争议上没有自己的立场。它恰当地支持两种选项,虽然它的缺省方式是执行复制。如果那不是你想要的,你必须让这个 class(类)带有一个 virtual base class(虚拟基类)的数据(也就是 File)。为了做到这一点,你要让从它直接继承的所有的 classes(类)使用 virtual inheritance(虚拟继承): class File { ... };class InputFile: virtual public File { ... };class OutputFile: virtual public File { ... };class IOFile: public InputFile,public OutputFile{ ... };    标准 C++ 库包含一个和此类似的 MI hierarchy(继承体系),只是那个 classes(类)是 class templates(类模板),名字是 basic_ios,basic_istream,basic_ostream 和 basic_iostream,而不是 File,InputFile,OutputFile 和 IOFile。   从正确行为的观点 看,public inheritance(公有继承)应该总是 virtual(虚拟)的。如果这是唯一的观点,规则就变得简单了:你使用 public inheritance(公有继承)的任何时候,都使用 virtual public inheritance(虚拟公有继承)。唉,正确性不是唯一的视角。避免 inherited fields(继承来的字段)复制需要在编译器的一部分做一些 behind-the-scenes legerdemain(幕后的戏法),而结果是从使用 virtual inheritance(虚拟继承)的 classes(类)创建的 objects(对象)通常比不使用 virtual inheritance(虚拟继承)的要大。访问 virtual base classes(虚拟基类)中的 data members(数据成员)也比那些 non-virtual base classes(非虚拟基类)中的要慢。编译器与编译器之间有一些细节不同,但基本的要点很清楚:virtual inheritance costs(虚拟继承要付出成本)。   它也有一些其它方面的成本。支配 initialization of virtual base classes(虚拟基类初始化)的规则比 non-virtual bases(非虚拟基类)的更加复杂而且更不直观。初始化一个 virtual base(虚拟基)的职责由 hierarchy(继承体系)中 most derived class(层次最低的派生类)承担。这个规则中包括的含义:   (1) 从需要 initialization(初始化)的 virtual bases(虚拟基)派生的 classes(类)必须知道它们的 virtual bases(虚拟基),无论它距离那个 bases(基)有多远;   (2) 当一个新的 derived class(派生类)被加入继承体系时,它必须为它的 virtual bases(虚拟基)(包括直接的和间接的)承担 initialization responsibilities(初始化职责)。    我对于 virtual base classes(虚拟基类)(也就是 virtual inheritance(虚拟继承))的建议很简单。首先,除非必需,否则不要使用 virtual bases(虚拟基)。缺省情况下,使用 non-virtual inheritance(非虚拟继承)。第二,如果你必须使用 virtual base classes(虚拟基类),试着避免在其中放置数据。这样你就不必在意它的 initialization(初始化)(以及它的 turns out(清空),assignment(赋值))规则中的一些怪癖。值得一提的是 Java 和 .NET 中的 Interfaces(接口)不允许包含任何数据,它们在很多方面可以和 C++ 中的 virtual base classes(虚拟基类)相比照。   现在我们使用下面的 C++ Interface class(接口类)(参见《C++箴言:最小化文件之间的编译依赖》)来为 persons(人)建模: class IPerson {public: virtual ~IPerson();  virtual std::string name() const = 0; virtual std::string birthDate() const = 0;};    IPerson 的客户只能使用 IPerson 的 pointers(指针)和 references(引用)进行编程,因为 abstract classes(抽象类)不能被实例化。为了创建能被当作 IPerson objects(对象)使用的 objects(对象),IPerson 的客户使用 factory functions(工厂函数)(再次参见 Item 31)instantiate(实例化)从 IPerson 派生的 concrete classes(具体类): // factory function to create a Person object from a unique database ID;// see Item 18 for why the return type isn't a raw pointerstd::tr1::shared_ptr makePerson(DatabaseID personIdentifier); // function to get a database ID from the userDatabaseID askUserForDatabaseID(); DatabaseID id(askUserForDatabaseID());std::tr1::shared_ptr pp(makePerson(id)); // create an object// supporting the// IPerson interface ... // manipulate *pp via// IPerson's member// functions   但是 makePerson 怎样创建它返回的 pointers(指针)所指向的 objects(对象)呢?显然,必须有一些 makePerson 可以实例化的从 IPerson 派生的 concrete class(具体类)。    假设这个 class(类)叫做 CPerson。作为一个 concrete class(具体类),CPerson 必须提供它从 IPerson 继承来的 pure virtual functions(纯虚拟函数)的 implementations(实现)。它可以从头开始写,但利用包含大多数或全部必需品的现有组件更好一些。例如,假设一个老式的 database-specific class(老式的数据库专用类)PersonInfo 提供了 CPerson 所需要的基本要素: class PersonInfo {public: explicit PersonInfo(DatabaseID pid); virtual ~PersonInfo();  virtual const char * theName() const; virtual const char * theBirthDate() const; ... private: virtual const char * valueDelimOpen() const; // see virtual const char * valueDelimClose() const; // below ...};    你可以看出这是一个老式的 class(类),因为 member functions(成员函数)返回 const char*s 而不是 string objects(对象)。尽管如此,如果鞋子合适,为什么不穿呢?这个 class(类)的 member functions(成员函数)的名字暗示结果很可能会非常合适。   你突然发现 PersonInfo 是设计用来帮助以不同的格式打印 database fields(数据库字段)的,每一个字段的值的开始和结尾通过指定的字符串定界。缺省情况下,字段值开始和结尾定界符是方括号,所以字段值 "Ring-tailed Lemur" 很可能被安排成这种格式: [Ring-tailed Lemur]   根据方括号并非满足 PersonInfo 的全体客户的期望的事实,virtual functions(虚拟函数)valueDelimOpen 和 valueDelimClose 允许 derived classes(派生类)指定它们自己的开始和结尾定界字符串。PersonInfo 的 member functions(成员函数)的 implementations(实现)调用这些 virtual functions(虚拟函数)在它们返回的值上加上适当的定界符。作为一个例子使用 PersonInfo::theName,代码如下: const char * PersonInfo::valueDelimOpen() const{ return "["; // default opening delimiter} const char * PersonInfo::valueDelimClose() const{ return "]"; // default closing delimiter} const char * PersonInfo::theName() const{ // reserve buffer for return value; because this is // static, it's automatically initialized to all zeros static char value[Max_Formatted_Field_Value_Length];  // write opening delimiter std::strcpy(value, valueDelimOpen());  append to the string in value this object's name field (being careful to avoid buffer overruns!)  // write closing delimiter std::strcat(value, valueDelimClose());  return value;}    有人可能会质疑 PersonInfo::theName 的陈旧的设计(特别是一个 fixed-size static buffer(固定大小静态缓冲区)的使用,这样的东西发生 overrun(越界)和 threading(线程)问题是比较普遍的——参见《C++箴言:必须返回对象时别返回引用》),但是请把这样的问题放到一边而注意这里:theName 调用 valueDelimOpen 生成它要返回的 string(字符串)的开始定界符,然后它生成名字值本身,然后它调用 valueDelimClose。   因为 valueDelimOpen 和 valueDelimClose 是 virtual functions(虚拟函数),theName 返回的结果不仅依赖于 PersonInfo,也依赖于从 PersonInfo 派生的 classes(类)。    对于 CPerson 的实现者,这是好消息,因为当细读 IPerson documentation(文档)中的 fine print(晦涩的条文)时,你发现 name 和 birthDate 需要返回未经修饰的值,也就是,不允许有定界符。换句话说,如果一个人的名字叫 Homer,对那个人的 name 函数的一次调用应该返回 "Homer",而不是 "[Homer]"。   CPerson 和 PersonInfo 之间的关系是 PersonInfo 碰巧有一些函数使得 CPerson 更容易实现。这就是全部。因而它们的关系就是 is-implemented-in-terms-of,而我们知道有两种方法可以表现这一点:经由 composition(复合)(参见《C++箴言:通过composition模拟“has-a”》)和经由 private inheritance(私有继承)(参见《C++箴言:谨慎使用私有继承》)。《C++箴言:谨慎使用私有继承》 指出 composition(复合)是通常的首选方法,但如果 virtual functions(虚拟函数)要被重定义,inheritance(继承)就是必不可少的。在当前情况下,CPerson 需要重定义 valueDelimOpen 和 valueDelimClose,所以简单的 composition(复合)做不到。最直截了当的解决方案是让 CPerson 从 PersonInfo privately inherit(私有继承),虽然 《C++箴言:谨慎使用私有继承》 说过只要多做一点工作,则 CPerson 也能用 composition(复合)和 inheritance(继承)的组合有效地重定义 PersonInfo 的 virtuals(虚拟函数)。这里,我们用 private inheritance(私有继承)。   但 是 CPerson 还必须实现 IPerson interface(接口),而这被称为 public inheritance(公有继承)。这就引出一个 multiple inheritance(多继承)的合理应用:组合 public inheritance of an interface(一个接口的公有继承)和 private inheritance of an implementation(一个实现的私有继承): class IPerson { // this class specifies thepublic: // interface to be implemented virtual ~IPerson();  virtual std::string name() const = 0; virtual std::string birthDate() const = 0;}; class DatabaseID { ... }; // used below; details are// unimportant class PersonInfo { // this class has functionspublic: // useful in implementing explicit PersonInfo(DatabaseID pid); // the IPerson interface virtual ~PersonInfo();  virtual const char * theName() const; virtual const char * theBirthDate() const;  virtual const char * valueDelimOpen() const; virtual const char * valueDelimClose() const; ...}; class CPerson: public IPerson, private PersonInfo { // note use of MIpublic: explicit CPerson( DatabaseID pid): PersonInfo(pid) {} virtual std::string name() const // implementations { return PersonInfo::theName(); } // of the required // IPerson member virtual std::string birthDate() const // functions { return PersonInfo::theBirthDate(); }private: // redefinitions of const char * valueDelimOpen() const { return ""; } // inherited virtual const char * valueDelimClose() const { return ""; } // delimiter}; // functions   在 UML 中,这个设计看起来像这样:   这个例子证明 MI 既是有用的,也是可理解的。    时至今日,multiple inheritance(多继承)不过是 object-oriented toolbox(面向对象工具箱)里的又一种工具而已,典型情况下,它的使用和理解更加复杂,所以如果你得到一个或多或少等同于一个 MI 设计的 SI 设计,则 SI 设计总是更加可取。如果你能拿出来的仅有的设计包含 MI,你应该更加用心地考虑一下——总会有一些方法使得 SI 也能做到。但同时,MI 有时是最清晰的,最易于维护的,最合理的完成工作的方法。在这种情况下,毫不畏惧地使用它。只是要确保谨慎地使用它。   Things to Remember   ·multiple inheritance(多继承)比 single inheritance(单继承)更复杂。它能导致新的歧义问题和对 virtual inheritance(虚拟继承)的需要。    ·virtual inheritance(虚拟继承)增加了 size(大小)和 speed(速度)成本,以及 initialization(初始化)和 assignment(赋值)的复杂度。当 virtual base classes(虚拟基类)没有数据时它是最适用的。   ·multiple inheritance(多继承)有合理的用途。一种方案涉及组合从一个 Interface class(接口类)的 public inheritance(公有继承)和从一个有助于实现的 class(类)的 private inheritance(私有继承)。 关于虚拟继承的思考虚拟继承在一般的应用中很少用到,所以也往往被忽视,这也主要是因为在C++中,多重继承是不推荐的,而一旦离开了多重继承,虚拟继承就完全失去了存在的必要(因为这样只会降低效率和占用更多的空间,实在是一无是处)。  以下面的一个例子为例:  #include   #include   class CA  {   int k; //为了便于说明后面的内存结构特别添加  public:   void f() {cout << "CA::f" << endl;}  };  class CB : public CA  {  };  class CC : public CA  {  };  class CD : public CB, public CC  {  };  void main()  {   CD d;   d.f();  }  当编译上述代码时,我们会收到如下的错误提示:  error C2385: 'CD::f' is ambiguous  即编译器无法确定你在d.f()中要调用的函数f到底是哪一个。这里可能会让人觉得有些奇怪,命名只定义了一个CA::f,既然大家都派生自CA,那自然就是调用的CA::f,为什么还无法确定呢?  这是因为编译器在进行编译的时候,需要确定子类的函数定义,如CA::f是确定的,那么在编译CB、CC时还需要在编译器的语法树中生成CB::f,CC::f等标识,那么,在编译CD的时候,由于CB、CC都有一个函数f,此时,编译器将试图生成两个CD::f标识,显然这时就要报错了。(当我们不使用CD::f的时候,以上标识都不会生成,所以,如果去掉d.f()一句,程序将顺利通过编译)  要解决这个问题,有两个方法:  1、重载函数f():此时由于我们明确定义了CD::f,编译器检查到CD::f()调用时就无需再像上面一样去逐级生成CD::f标识了;  此时CD的元素结构如下:  --------  |CB(CA)|  |CC(CA)|  --------  故此时的sizeof(CD) = 8;(CB、CC各有一个元素k)  2、使用虚拟继承:虚拟继承又称作共享继承,这种共享其实也是编译期间实现的,当使用虚拟继承时,上面的程序将变成下面的形式:  #include   #include   class CA  {   int k;  public:   void f() {cout << "CA::f" << endl;}  };  class CB : virtual public CA  {  };  class CC : virtual public CA  {  };  class CD : public CB, public CC  {  };  void main()  {   CD d;   d.f();  }  此时,当编译器确定d.f()调用的具体含义时,将生成如下的CD结构:  ----  |CB|  |CC|  |CA|  ----  同时,在CB、CC中都分别包含了一个指向CA的vbptr(virtual base table pointer),其中记录的是从CB、CC的元素到CA的元素之间的偏移量。此时,不会生成各子类的函数f标识,除非子类重载了该函数,从而达到“共享”的目的。  也正因此,此时的sizeof(CD) = 12(两个vbptr + sizoef(int));
a123456678 2019-12-02 01:58:07 0 浏览量 回答数 0

回答

如大家所知道的,Mysql目前主要有以下几种索引类型:FULLTEXT,HASH,BTREE,RTREE。 那么,这几种索引有什么功能和性能上的不同呢? FULLTEXT 即为全文索引,目前只有MyISAM引擎支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不过目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引。值得一提的是,在数据量较大时候,现将数据放入一个没有全局索引的表中,然后再用CREATE INDEX创建FULLTEXT索引,要比先为一张表建立FULLTEXT然后再将数据写入的速度快很多。 全文索引并不是和MyISAM一起诞生的,它的出现是为了解决WHERE name LIKE “%word%"这类针对文本的模糊查询效率较低的问题。在没有全文索引之前,这样一个查询语句是要进行遍历数据表操作的,可见,在数据量较大时是极其的耗时的,如果没有异步IO处理,进程将被挟持,很浪费时间,当然这里不对异步IO作进一步讲解,想了解的童鞋,自行谷哥。 全文索引的使用方法并不复杂: 创建ALTER TABLE table ADD INDEX FULLINDEX USING FULLTEXT(cname1[,cname2…]); 使用SELECT * FROM table WHERE MATCH(cname1[,cname2…]) AGAINST ('word' MODE ); 其中, MODE为搜寻方式(IN BOOLEAN MODE ,IN NATURAL LANGUAGE MODE ,IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION / WITH QUERY EXPANSION)。 关于这三种搜寻方式,愚安在这里也不多做交代,简单地说,就是,布尔模式,允许word里含一些特殊字符用于标记一些具体的要求,如+表示一定要有,-表示一定没有,*表示通用匹配符,是不是想起了正则,类似吧;自然语言模式,就是简单的单词匹配;含表达式的自然语言模式,就是先用自然语言模式处理,对返回的结果,再进行表达式匹配。 对搜索引擎稍微有点了解的同学,肯定知道分词这个概念,FULLTEXT索引也是按照分词原理建立索引的。西文中,大部分为字母文字,分词可以很方便的按照空格进行分割。但很明显,中文不能按照这种方式进行分词。那又怎么办呢?这个向大家介绍一个Mysql的中文分词插件Mysqlcft,有了它,就可以对中文进行分词,想了解的同学请移步Mysqlcft,当然还有其他的分词插件可以使用。 HASH Hash这个词,可以说,自打我们开始码的那一天起,就开始不停地见到和使用到了。其实,hash就是一种(key=>value)形式的键值对,如数学中的函数映射,允许多个key对应相同的value,但不允许一个key对应多个value。正是由于这个特性,hash很适合做索引,为某一列或几列建立hash索引,就会利用这一列或几列的值通过一定的算法计算出一个hash值,对应一行或几行数据(这里在概念上和函数映射有区别,不要混淆)。在java语言中,每个类都有自己的hashcode()方法,没有显示定义的都继承自object类,该方法使得每一个对象都是唯一的,在进行对象间equal比较,和序列化传输中起到了很重要的作用。hash的生成方法有很多种,足可以保证hash码的唯一性,例如在MongoDB中,每一个document都有系统为其生成的唯一的objectID(包含时间戳,主机散列值,进程PID,和自增ID)也是一种hash的表现。额,我好像扯远了-_-! 由于hash索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。那为什么还需要其他的树形索引呢? 在这里愚安就不自己总结了。引用下园子里其他大神的文章:来自 14的路 的MySQL的btree索引和hash索引的区别 (1)Hash 索引仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询。 由于 Hash 索引比较的是进行 Hash 运算之后的 Hash 值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的 Hash 算法处理之后的 Hash 值的大小关系,并不能保证和Hash运算前完全一样。 (2)Hash 索引无法被用来避免数据的排序操作。 由于 Hash 索引中存放的是经过 Hash 计算之后的 Hash 值,而且Hash值的大小关系并不一定和 Hash 运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算; (3)Hash 索引不能利用部分索引键查询。 对于组合索引,Hash 索引在计算 Hash 值的时候是组合索引键合并后再一起计算 Hash 值,而不是单独计算 Hash 值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash 索引也无法被利用。 (4)Hash 索引在任何时候都不能避免表扫描。 前面已经知道,Hash 索引是将索引键通过 Hash 运算之后,将 Hash运算结果的 Hash 值和所对应的行指针信息存放于一个 Hash 表中,由于不同索引键存在相同 Hash 值,所以即使取满足某个 Hash 键值的数据的记录条数,也无法从 Hash 索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较,并得到相应的结果。 (5)Hash 索引遇到大量Hash值相等的情况后性能并不一定就会比B-Tree索引高。 对于选择性比较低的索引键,如果创建 Hash 索引,那么将会存在大量记录指针信息存于同一个 Hash 值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据的访问,而造成整体性能低下。 愚安我稍作补充,讲一下HASH索引的过程,顺便解释下上面的第4,5条: 当我们为某一列或某几列建立hash索引时(目前就只有MEMORY引擎显式地支持这种索引),会在硬盘上生成类似如下的文件: hash值 存储地址 1db54bc745a1 77#45b5 4bca452157d4 76#4556,77#45cc… … hash值即为通过特定算法由指定列数据计算出来,磁盘地址即为所在数据行存储在硬盘上的地址(也有可能是其他存储地址,其实MEMORY会将hash表导入内存)。 这样,当我们进行WHERE age = 18 时,会将18通过相同的算法计算出一个hash值==>在hash表中找到对应的储存地址==>根据存储地址取得数据。 所以,每次查询时都要遍历hash表,直到找到对应的hash值,如(4),数据量大了之后,hash表也会变得庞大起来,性能下降,遍历耗时增加,如(5)。 BTREE BTREE索引就是一种将索引值按一定的算法,存入一个树形的数据结构中,相信学过数据结构的童鞋都对当初学习二叉树这种数据结构的经历记忆犹新,反正愚安我当时为了软考可是被这玩意儿好好地折腾了一番,不过那次考试好像没怎么考这个。如二叉树一样,每次查询都是从树的入口root开始,依次遍历node,获取leaf。 BTREE在MyISAM里的形式和Innodb稍有不同 在 Innodb里,有两种形态:一是primary key形态,其leaf node里存放的是数据,而且不仅存放了索引键的数据,还存放了其他字段的数据。二是secondary index,其leaf node和普通的BTREE差不多,只是还存放了指向主键的信息. 而在MyISAM里,主键和其他的并没有太大区别。不过和Innodb不太一样的地方是在MyISAM里,leaf node里存放的不是主键的信息,而是指向数据文件里的对应数据行的信息. RTREE RTREE在mysql很少使用,仅支持geometry数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种。 相对于BTREE,RTREE的优势在于范围查找. 各种索引的使用情况 (1)对于BTREE这种Mysql默认的索引类型,具有普遍的适用性 (2)由于FULLTEXT对中文支持不是很好,在没有插件的情况下,最好不要使用。其实,一些小的博客应用,只需要在数据采集时,为其建立关键字列表,通过关键字索引,也是一个不错的方法,至少愚安我是经常这么做的。 (3)对于一些搜索引擎级别的应用来说,FULLTEXT同样不是一个好的处理方法,Mysql的全文索引建立的文件还是比较大的,而且效率不是很高,即便是使用了中文分词插件,对中文分词支持也只是一般。真要碰到这种问题,Apache的Lucene或许是你的选择。 (4)正是因为hash表在处理较小数据量时具有无可比拟的素的优势,所以hash索引很适合做缓存(内存数据库)。如mysql数据库的内存版本Memsql,使用量很广泛的缓存工具Mencached,NoSql数据库redis等,都使用了hash索引这种形式。当然,不想学习这些东西的话Mysql的MEMORY引擎也是可以满足这种需求的。 (5)至于RTREE,愚安我至今还没有使用过,它具体怎么样,我就不知道了。有RTREE使用经历的同学,到时可以交流下! 答案来源于网络
养狐狸的猫 2019-12-02 02:18:32 0 浏览量 回答数 0

回答

先学好语言,这是学习的基础。 有些算法书上在学习语言部分会有一点算法包含在内,比如递归。 要学算法,先练好递归,这会对你深入学习其他算法有很大的帮助。 树形结构是数据结构中较难的部分,也是数据结构的基础,主要靠练。 还有就是,不要总是学习理论,合上书本认真地把算法用代码和实现是最重要的。 不要背代码,没用的,注重理解。 刚开始会有些不习惯,学得多了就好了。 ------------------------------------------------------------------------------------------- 内容出自http://www.zhihu.com/question/19830721 希望对你有帮助 1. 程序 = 数据结构 + 算法 2. 学习:刚开始看时肯定会有些不清楚,因为你是刚学完 语言,对语言还不太熟练。你学习数据结构时找一本经典的数据结构书,看完一个数据结构后用语言将其实现。开始时的实现肯定会有困难,那么请百度下会有很多优秀的数据结构源码的。你可以模仿这些优秀的源码写。请记住一定要开始时自己实现,当被卡住了就看一下源码,看看自己被卡在了什么地方,引起注意以便下次自己会写。当你把书上的数据结构源码写了一遍之后,你已经超过了你绝大部分的同学。 3. 运用: 这时你就需要对这些数据结构加以运用,你可以在百度上搜索“某个数据结构 + ACM”,你就会看到一些题目,这些题目都是数据结构的运用,甚至有这些数据结构的变形。每种数据结构做5题左右。期间你还会遇到程序另一重要的方面算法,有不会的就 百度。 期间可以学到的数据结构和算法做小软件玩儿,例如压缩软件,五子棋之类的。 4. 深入: 当你完成了第三步你已经是你们学校的小高手了。这时看你的方向如果这时发现自己喜欢 ACM 的话就去搞 ACM,如果不感兴趣,就找自己感兴趣的技术学习一下,做几个完整的项目,例如写个编译器,或者实现一个简单的编程语言。 总结:无论选择哪条道路只要按照这些做了,你毕业后肯定会成为抢手货。 ------------------------------------------------------------------------------------------- 也就这样了: 时间并不会因为你的迷茫和迟疑而停留, 就在你看这篇文章的同时, 不知道有多少人在冥思苦想, 在为算法废寝忘食, 不知道有多少人在狂热地拍着代码, 不知道又有多少提交一遍又一遍地刷新着OJ的status页面…… 没有谁生来就是神牛, 而千里之行, 始于足下。 我期盼NOIP一等榜上有你(虽然我不知道你叫什么)。
游客886 2019-12-02 01:22:04 0 浏览量 回答数 0

回答

从最终的过滤效果来看,其实使用正则是比分词后更好的. 例如:骂人,假设是一个敏感词,如果写成:"骂 人", jcseg是会切分成 骂/ 人/ 两个词条的. 但是实际上,人还是会看成本身的意思,而"/骂\s{1,}人/"这个正则 则可以过滤掉. 目前我使用的方法也是正则,如果你要使用Jcseg,Jcseg从1.9.4开始支持检测模式切分,正好可以用于这个需求:也就是直接返回词库中有的词条,你将所有的敏感词加入到词库中,只要返回了词条就是敏感词. 具体还是要考虑你的使用场合吧. ######回复 @Tek_Eternal : 过奖了,其实我很早就看到你的提问了。苦于新安装的系统无法输入中文。 是一个有效的方法。。######jcseg作者亲自回答,真荣幸:) 确实目前我的需求比较简单,只是从一个短文本中找出有没有敏感词而已。昨天查了很多资料,最后决定还是先用把敏感词载入做成一个关联数组和索引数组,然后对目标文本进行逐字逐词查敏感词索引的方法来做。 参考了 http://bbs.9ria.com/thread-88142-1-1.html 这个帖子里的方法。以后如果有更复杂的需求,还是会考虑分词处理一下######以前好像看到过一个方案,但敏感词没有等级之说,只要你先把词库set进类中,然后传入文本,它就会反馈出现过1次以上的敏感词,并返回出词和出现的次数。你搜搜,好像是用树形节点实现的算法,貌似非常快。######谢谢,我说的等级可能就是频次吧,第一次接触这块,没啥概念。######应该要用正则表达式吧?######http://www.cnblogs.com/chenssy/p/3751221.html#2966041######不要忽略网民的智慧######这个我也做过,我是用的多模匹配,wumamber算法,如果敏感词典不是很大的话可以试试。######正则在过滤词组多的时候,效率很慢。 分词相对更准确,比如是‘他妈`是过滤词,那么,那个弹吉他妈妈唱的真好听。就不会被过滤,而正则就肯定匹配上了。
kun坤 2020-06-01 09:47:45 0 浏览量 回答数 0

回答

摘要:面试也是一门学问,在面试之前做好充分的准备则是成功的必须条件,而程序员在代码面试时,常会遇到编写算法的相关问题,比如排序、二叉树遍历等等。 在程序员的职业生涯中,算法亦算是一门基础课程,尤其是在面试的时候,很多公司都会让程序员编写一些算法实例,例如快速排序、二叉树查找等等。 本文总结了程序员在代码面试中最常遇到的10大算法类型,想要真正了解这些算法的原理,还需程序员们花些功夫。 1.String/Array/Matrix 在Java中,String是一个包含char数组和其它字段、方法的类。如果没有IDE自动完成代码,下面这个方法大家应该记住: String/arrays很容易理解,但与它们有关的问题常常需要高级的算法去解决,例如动态编程、递归等。 下面列出一些需要高级算法才能解决的经典问题: Evaluate Reverse Polish Notation Longest Palindromic Substring 单词分割 字梯 Median of Two Sorted Arrays 正则表达式匹配 合并间隔 插入间隔 Two Sum 3Sum 4Sum 3Sum Closest String to Integer 合并排序数组 Valid Parentheses 实现strStr() Set Matrix Zeroes 搜索插入位置 Longest Consecutive Sequence Valid Palindrome 螺旋矩阵 搜索一个二维矩阵 旋转图像 三角形 Distinct Subsequences Total Maximum Subarray 删除重复的排序数组 删除重复的排序数组2 查找没有重复的最长子串 包含两个独特字符的最长子串 Palindrome Partitioning 2.链表 在Java中实现链表是非常简单的,每个节点都有一个值,然后把它链接到下一个节点。 class Node { int val; Node next; Node(int x) { val = x; next = null; } } 比较流行的两个链表例子就是栈和队列。 栈(Stack) class Stack{ Node top; public Node peek(){ if(top != null){ return top; } return null; } public Node pop(){ if(top == null){ return null; }else{ Node temp = new Node(top.val); top = top.next; return temp; } } public void push(Node n){ if(n != null){ n.next = top; top = n; } } } 队列(Queue) class Queue{ Node first, last;   public void enqueue(Node n){ if(first == null){ first = n; last = first; }else{ last.next = n; last = n; } }   public Node dequeue(){ if(first == null){ return null; }else{ Node temp = new Node(first.val); first = first.next; return temp; } } } 值得一提的是,Java标准库中已经包含一个叫做Stack的类,链表也可以作为一个队列使用(add()和remove())。(链表实现队列接口)如果你在面试过程中,需要用到栈或队列解决问题时,你可以直接使用它们。 在实际中,需要用到链表的算法有: 插入两个数字 重新排序列表 链表周期 Copy List with Random Pointer 合并两个有序列表 合并多个排序列表 从排序列表中删除重复的 分区列表 LRU缓存 3.树&堆 这里的树通常是指二叉树。 class TreeNode{ int value; TreeNode left; TreeNode right; } 下面是一些与二叉树有关的概念: 二叉树搜索:对于所有节点,顺序是:left children <= current node <= right children; 平衡vs.非平衡:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树; 满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点; 完美二叉树(Perfect Binary Tree):一个满二叉树,所有叶子都在同一个深度或同一级,并且每个父节点都有两个子节点; 完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。 堆(Heap)是一个基于树的数据结构,也可以称为优先队列( PriorityQueue),在队列中,调度程序反复提取队列中第一个作业并运行,因而实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权。堆即为解决此类问题设计的一种数据结构。 下面列出一些基于二叉树和堆的算法: 二叉树前序遍历 二叉树中序遍历 二叉树后序遍历 字梯 验证二叉查找树 把二叉树变平放到链表里 二叉树路径和 从前序和后序构建二叉树 把有序数组转换为二叉查找树 把有序列表转为二叉查找树 最小深度二叉树 二叉树最大路径和 平衡二叉树 4.Graph 与Graph相关的问题主要集中在深度优先搜索和宽度优先搜索。深度优先搜索非常简单,你可以从根节点开始循环整个邻居节点。下面是一个非常简单的宽度优先搜索例子,核心是用队列去存储节点。 第一步,定义一个GraphNode class GraphNode{ int val; GraphNode next; GraphNode[] neighbors; boolean visited; GraphNode(int x) { val = x; } GraphNode(int x, GraphNode[] n){ val = x; neighbors = n; } public String toString(){ return "value: "+ this.val; } } 第二步,定义一个队列 class Queue{ GraphNode first, last; public void enqueue(GraphNode n){ if(first == null){ first = n; last = first; }else{ last.next = n; last = n; } } public GraphNode dequeue(){ if(first == null){ return null; }else{ GraphNode temp = new GraphNode(first.val, first.neighbors); first = first.next; return temp; } } } 第三步,使用队列进行宽度优先搜索 public class GraphTest { public static void main(String[] args) { GraphNode n1 = new GraphNode(1); GraphNode n2 = new GraphNode(2); GraphNode n3 = new GraphNode(3); GraphNode n4 = new GraphNode(4); GraphNode n5 = new GraphNode(5); n1.neighbors = new GraphNode[]{n2,n3,n5}; n2.neighbors = new GraphNode[]{n1,n4}; n3.neighbors = new GraphNode[]{n1,n4,n5}; n4.neighbors = new GraphNode[]{n2,n3,n5}; n5.neighbors = new GraphNode[]{n1,n3,n4}; breathFirstSearch(n1, 5); } public static void breathFirstSearch(GraphNode root, int x){ if(root.val == x) System.out.println("find in root"); Queue queue = new Queue(); root.visited = true; queue.enqueue(root); while(queue.first != null){ GraphNode c = (GraphNode) queue.dequeue(); for(GraphNode n: c.neighbors){ if(!n.visited){ System.out.print(n + " "); n.visited = true; if(n.val == x) System.out.println("Find "+n); queue.enqueue(n); } } } } } 输出结果: value: 2 value: 3 value: 5 Find value: 5 value: 4 实际中,基于Graph需要经常用到的算法: 克隆Graph 15 2014-04-24 18:55:03回复数 293 只看楼主 引用 举报 楼主 柔软的胖纸 Bbs1 5.排序 不同排序算法的时间复杂度,大家可以到wiki上查看它们的基本思想。 BinSort、Radix Sort和CountSort使用了不同的假设,所有,它们不是一般的排序方法。 下面是这些算法的具体实例,另外,你还可以阅读:Java开发者在实际操作中是如何排序的。 归并排序 快速排序 插入排序 6.递归和迭代 下面通过一个例子来说明什么是递归。 问题: 这里有n个台阶,每次能爬1或2节,请问有多少种爬法? 步骤1:查找n和n-1之间的关系 为了获得n,这里有两种方法:一个是从第一节台阶到n-1或者从2到n-2。如果f(n)种爬法刚好是爬到n节,那么f(n)=f(n-1)+f(n-2)。 步骤2:确保开始条件是正确的 f(0) = 0; f(1) = 1; public static int f(int n){ if(n <= 2) return n; int x = f(n-1) + f(n-2); return x; } 递归方法的时间复杂度指数为n,这里会有很多冗余计算。 f(5) f(4) + f(3) f(3) + f(2) + f(2) + f(1) f(2) + f(1) + f(2) + f(2) + f(1) 该递归可以很简单地转换为迭代。 public static int f(int n) { if (n <= 2){ return n; } int first = 1, second = 2; int third = 0; for (int i = 3; i <= n; i++) { third = first + second; first = second; second = third; } return third; } 在这个例子中,迭代花费的时间要少些。关于迭代和递归,你可以去 这里看看。 7.动态规划 动态规划主要用来解决如下技术问题: 通过较小的子例来解决一个实例; 对于一个较小的实例,可能需要许多个解决方案; 把较小实例的解决方案存储在一个表中,一旦遇上,就很容易解决; 附加空间用来节省时间。 上面所列的爬台阶问题完全符合这四个属性,因此,可以使用动态规划来解决: public static int[] A = new int[100]; public static int f3(int n) { if (n <= 2) A[n]= n; if(A[n] > 0) return A[n]; else A[n] = f3(n-1) + f3(n-2);//store results so only calculate once! return A[n]; } 一些基于动态规划的算法: 编辑距离 最长回文子串 单词分割 最大的子数组 8.位操作 位操作符: 从一个给定的数n中找位i(i从0开始,然后向右开始) public static boolean getBit(int num, int i){ int result = num & (1<<i); if(result == 0){ return false; }else{ return true; } } 例如,获取10的第二位: i=1, n=10 1<<1= 10 1010&10=10 10 is not 0, so return true; 典型的位算法: Find Single Number Maximum Binary Gap 9.概率 通常要解决概率相关问题,都需要很好地格式化问题,下面提供一个简单的例子: 有50个人在一个房间,那么有两个人是同一天生日的可能性有多大?(忽略闰年,即一年有365天) 算法: public static double caculateProbability(int n){ double x = 1; for(int i=0; i<n; i++){ x *= (365.0-i)/365.0; } double pro = Math.round((1-x) * 100); return pro/100; } 结果:calculateProbability(50) = 0.97 10.组合和排列 组合和排列的主要差别在于顺序是否重要。 例1: 1、2、3、4、5这5个数字,输出不同的顺序,其中4不可以排在第三位,3和5不能相邻,请问有多少种组合? 例2: 有5个香蕉、4个梨、3个苹果,假设每种水果都是一样的,请问有多少种不同的组合? 基于它们的一些常见算法 排列 排列2 排列顺序 来自: ProgramCreek 转载于:https://bbs.csdn.net/topics/390768965
养狐狸的猫 2019-12-02 02:11:29 0 浏览量 回答数 0

问题

去粗取精,云效打造独特测试用例管理工具

       测试用例是软件测试的核心,有了测试用例,无论谁来测试,参照测试用例实施,都能保障测试的质量。目前市面上常见的测试用例管理工具有很多,如TestManager...
技术小菜鸟 2019-12-01 21:40:05 3576 浏览量 回答数 1

回答

ThreadGroup概述在java中为了方便线程管理出现了线程组ThreadGroup的概念,每个ThreadGroup可以同时包含多个子线程和多个子线程组,在一个进程中线程组是以树形的方式存在,通常情况下根线程组是system。system线程组下是main线程组,默认情况下第一级应用自己的线程组是通过main线程组创建出来的。 public class ThreadGroupTest { public static void main(String[] args) throws InterruptedException { //主线程对应的线程组 printGroupInfo(Thread.currentThread());//线程组为main父线程组为system //新建线程,系统默认的线程组 Thread appThread = new Thread(()->{},"appThread"); printGroupInfo(appThread);//线程组为main父线程组为system //自定义线程组 ThreadGroup factoryGroup=new ThreadGroup("factory"); Thread workerThread=new Thread(factoryGroup,()->{},"worker"); printGroupInfo(workerThread);//线程组为factory,父线程组为main //设置父线程组 ThreadGroup deviceGroup=new ThreadGroup(factoryGroup,"device"); Thread pcThread=new Thread(deviceGroup,()->{},"pc"); printGroupInfo(pcThread);//线程组为device,父线程组为factory } static void printGroupInfo(Thread t) { ThreadGroup group = t.getThreadGroup(); System.out.println("thread " + t.getName() + " group name is "+ group.getName() + " max priority is " + group.getMaxPriority() + " thread count is " + group.activeCount() + " parent group is "+ (group.getParent()==null?null:group.getParent().getName())); ThreadGroup parent=group; do { ThreadGroup current = parent; parent = parent.getParent(); if (parent == null) { break; } System.out.println(current.getName() +" Group's parent group name is "+parent.getName()); } while (true); System.out.println("--------------------------"); } }ThreadGroup线程组的操作线程组信息的获取 public int activeCount(); // 获得当前线程组中线程数目, 包括可运行和不可运行的public int activeGroupCount(); //获得当前线程组中活动的子线程组的数目public int enumerate(Thread list[]); //列举当前线程组中的线程public int enumerate(ThreadGroup list[]); //列举当前线程组中的子线程组public final int getMaxPriority(); //获得当前线程组中最大优先级public final String getName(); //获得当前线程组的名字public final ThreadGroup getParent(); //获得当前线程组的父线程组public boolean parentOf(ThreadGroup g); //判断当前线程组是否为指定线程的父线程public boolean isDaemon(); //判断当前线程组中是否有监护线程public void list(); //列出当前线程组中所有线程和子线程名线程组的操作 public final void resume(); //使被挂起的当前组内的线程恢复到可运行状态public final void setDaemon (boolean daemon); //指定一个线程为当前线程组的监护线程public final void setMaxPriority(int pri); //设置当前线程组允许的最大优先级public final void stop();//终止当前线程组中所有线程public final void suspend(); //挂起当前线程组中所有线程public String toStrinng(); //将当前线程组转换为String类的对象public class ThreadGroupDemo { public static void main(String[] args) throws InterruptedException { // 创建5个线程,并入group里面进行管理 ThreadGroup threadGroup = new ThreadGroup("threadGroupTest1"); for (int i = 0; i < 5; i++) { Thread thread = new Thread(threadGroup,()->{ System.out.println("Thread Start " + Thread.currentThread().getName()); try { int value = (int)new Random((new Date()).getTime()).nextDouble()*100; System.out.printf("Thread %s doTask: %d\n", Thread.currentThread().getName(),value); TimeUnit.SECONDS.sleep(value); } catch (InterruptedException e) { System.out.printf("Thread %s: Interrupted\n", Thread.currentThread().getName()); return; } System.out.println("Thread end " + Thread.currentThread().getName()); }); thread.start(); TimeUnit.SECONDS.sleep(1); } //group信息 System.out.printf("Number of Threads: %d\n", threadGroup.activeCount()); System.out.printf("Information about the Thread Group\n"); threadGroup.list(); //复制group的thread信息 Thread[] threads = new Thread[threadGroup.activeCount()]; threadGroup.enumerate(threads); for (int i = 0; i < threadGroup.activeCount(); i++) { System.out.printf("Thread %s: %s\n", threads[i].getName(),threads[i].getState()); } //等待结束 while (threadGroup.activeCount() > 9) { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } //中断group中的线程 threadGroup.interrupt(); } }
auto_answer 2019-12-02 01:49:32 0 浏览量 回答数 0
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 企业建站模板