遍历

错题本——数据结构(树)

不羁的心 提交于 2020-02-15 08:24:41
树 在任意一棵非空二叉排序树T1中, 删除某结点v之后形成二叉排序树 T2,再将v 插入T2形成二叉排序树T3。下列关于T1与T3的叙述中,正确的是( )。 I.若 v 是 T1的叶结点,则 T1 与 T3 不同 II. 若 v 是 T1的叶结点,则 T1与 T3相同 III.若 v 不是 T1 的叶结点,则 T1 与 T3 不同 IV.若v 不是 T1 的叶结点,则 T1 与 T3 相同 解析: 以下说法正确的是( )。 A 若有一个结点是二叉树中某个子树的中序遍历结果序列的最后一个结点,则它一定是该子树的前序遍历结果序列的最后一个结点。 B 若有一个结点是二叉树中某个子树的前序遍历结果序列的最后一个结点,则它一定是该子树的中序遍历结果序列的最后一个结点。 C 若有一个页子结点是二叉树中某个子树的中序遍历结果序列的最后一个结点,则它一定是该子树的前序遍历结果序列的最后一个结点。 D 若有一个页子结点是二叉树中某个子树的前序遍历结果序列的最后一个结点,则它一定是该子树的中序遍历结果序列的最后一个结点。 解析: A:中序遍历结果为AB,前序遍历结果为BA,因此错误 B:前序遍历结果为BA,中序遍历结果为AB,因此错误 C:中序遍历的情况下,固定了叶子结点为最后一个结点,因此一定有右子树,中序遍历和前序遍历的顺序都是将右子树放在最后一个,因此C正确 D:前序遍历的情况下

ES6 Map数据结构

左心房为你撑大大i 提交于 2020-02-15 03:20:55
Map JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。 ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。 const m = new Map(); const o = {p:"hello world"}; m.set(o,'content'); console.log(m.get(o)); // content console.log(m.has(o)); // true console.log(m.delete(o)); // true console.log(m.has(o)); // false 上面代码使用 Map 结构的set方法,将对象o当作m的一个键,然后又使用get方法读取这个键,接着使用delete方法删除了这个键。 上面的例子展示了如何向 Map 添加成员。作为构造函数,Map 也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。 const map = new Map([[

集合知识点

≯℡__Kan透↙ 提交于 2020-02-15 01:47:22
HashMap底层 1.8前数组+链表 1.8后数组+链表/红黑树 当添加一个元素(key-value)时,就首先计算元素key的hash值,以此确定插入数组中的位置,但是可能存在同一hash值的元素已经被放在数组同一位置了,这时就添加到同一hash值的元素的后面,他们在数组的同一位置,但是形成了链表,同一各链表上的Hash值是相同的,所以说数组存放的是链表。而当链表长度太长时,链表就转换为红黑树,这样大大提高了查找的效率。 负载因子 HashMap所能容纳的最大数据量=length*负载因子(默认是0.75) 超过这个数目就要进行扩容(resize),扩容后的HashMap容量是之前容量的两倍。 负载因子过小,扩容就会很快,可能内存紧张;负载因子过大,就会扩容慢,造成时间效率低。 HashMap 的长度为什么是2的幂次方 因为hash值很大,能拿来直接用来做数组下标。所以令table数组下标i = (length-1)&hash,length-1后就能保证全为1,与操作之后,能保证散列的均匀,同时与运算效率高。 迭代器 迭代器是一个对象,他的工作是遍历并选择序列中的对象。开发人员不需要知道容器底层结构,就可以实现对容器的遍历。 Iterator只能正向遍历集合,ListIterato继承自Iterator,专门针对List,可以从两个方向来遍历List,同时支持元素修改。

非递归方式实现树的遍历

天大地大妈咪最大 提交于 2020-02-14 23:08:26
本文转载自作者:hzhu212 链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/yan-se-biao-ji-fa-yi-chong-tong-yong-qie-jian-ming/ 来源:力扣(LeetCode) 官方题解中介绍了三种方法来完成树的中序遍历,包括: 递归 借助栈的迭代方法 莫里斯遍历 在树的深度优先遍历中(包括前序、中序、后序遍历),递归方法最为直观易懂,但考虑到效率,我们通常不推荐使用递归。 栈迭代方法虽然提高了效率,但其嵌套循环却非常烧脑,不易理解,容易造成“一看就懂,一写就废”的窘况。而且对于不同的遍历顺序(前序、中序、后序),循环结构差异很大,更增加了记忆负担。 因此,我在这里介绍一种“颜色标记法”(瞎起的名字……),兼具栈迭代方法的高效,又像递归方法一样简洁易懂,更重要的是,这种方法对于前序、中序、后序遍历,能够写出完全一致的代码。 其核心思想如下: 使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。 如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。 如果遇到的节点为灰色,则将节点的值输出。 使用这种方法实现的中序遍历如下: class Solution : def inorderTraversal ( self

Java--数据结构之二叉搜索树

空扰寡人 提交于 2020-02-14 16:22:11
一、二叉搜索树Binary Search Tree 1、若左子树不为空,则左子树上所有节点的值均小于或等于它的根节点的值。 2、若右子树不为空,则右子树上所有节点的值均大于或等于它的根节点的值。 3、左、右子树也分别为二叉搜索树。 二、节点域设置 //根节点 private Entry < T > root ; //初始化 public BSTDemo ( ) { this . root = null ; } //节点域 public class Entry < T extends Comparable < T > > { private T data ; //数据域 private Entry < T > left ; //左孩子域 private Entry < T > right ; //右孩子域 public Entry ( ) { this ( null , null , null ) ; } public Entry ( T data , Entry < T > left , Entry < T > right ) { this . data = data ; this . left = left ; this . right = right ; } } 三、递归和非递归操作BST 1、插入 (1)递归插入 //插入 public void insert ( T val

Redis使用

僤鯓⒐⒋嵵緔 提交于 2020-02-14 05:53:05
存储用户信息时 方案一:key-value形式存储,key为用户id,value为用户结构信息序列化后的字符串内容 方案二:hash存储,子key为用户id,value为用户结构信息,无需序列化 方案一在存取时需要序列化与反序列化;且key可不唯一,用户id存储可能重复;并发操作时需要将整个对象取回并对修改操作作并发保护。 方案二可防重,且不存在序列化开销,没有并发修改控制问题 TODO 这里有个问题,网上说hash可以避免cas问题,怎么体现的 分布式锁 用于控制并发流程,如多个线程需要频繁对某个数据进行读取和修改引起的并发问题,使用分布式锁可保证原子操作即执行某一过程不会因线程切换而打断。 实现:setnx(set if not exits)一个时间只允许设置一个锁,用完了del指令释放 setnx lockKey true del lockKey 问题一:如果在获得锁后发生事故导致del指令没能执行,那么会引起死锁问题,锁不能被释放,下一个线程永远拿不到 解决一:在获取锁的同时设置一个过期时间expire lockKey seconds,保证发生异常不能主动释放锁也能自动释放 问题二:虽然设置了过期时间保证自动释放锁,但如果在exprie前服务进程挂了,也是会引起死锁的,因为expire和setnx指令不是原子指令不能一起执行 (TODO 不使用Redis事务的原因) 解决二

PAT甲级1086 Tree Traversals Again

别说谁变了你拦得住时间么 提交于 2020-02-13 17:25:36
本题考查 二叉树、中序遍历 思路 思路一句话:“根据二叉树中序遍历非递归代码生成二叉树并对其进行后序遍历” 如何根据二叉树中序遍历非递归代码生成二叉树? 建立两个变量preCal与pre分别记录上一次操作的类型与操作的结点索引。 分两种情况讨论: 如果当前操作是“push”的话 如果上一次的操作是push,则本次push结点是上个操作结点的左孩子 如果上一次的操作是pop,则本次push结点是上个pop出的结点的右孩子 如果当前操作是“pop”的话 更新preCal与pre的值 AC代码 import java . util . Scanner ; import java . util . Stack ; public class Main { static String result = "" ; static class Node { int key ; Node leftChild ; Node rightChild ; public Node ( ) { this . key = - 1 ; this . leftChild = null ; this . rightChild = null ; } } static void postOrder ( Node root ) { if ( root . leftChild != null ) postOrder ( root

LinkList

試著忘記壹切 提交于 2020-02-13 17:18:57
for顺序遍历耗时 > iterator迭代器遍历耗时 > 通过removeFirst()或removeLast()遍历耗时 > forach顺序遍历耗时 = 通过pollFirst()或pollLast()来遍历耗时。 import java . util . ArrayList ; import java . util . Collections ; import java . util . Comparator ; import java . util . Iterator ; import java . util . LinkedList ; public class Test { public static void main ( String [ ] args ) { //创建存放int类型的linkedList LinkedList < Integer > linkedList = new LinkedList < Integer > ( ) ; for ( int i = 20 ; i < 100 ; i ++ ) { linkedList . add ( i ) ; } //添加元素到列表开头 linkedList . addFirst ( 0 ) ; System . out . println ( "添加元素到列表开头:" + linkedList ) ; /

Generator

血红的双手。 提交于 2020-02-13 05:00:14
基本概念 Generator函数是ES6提供的一种异步编程解决办法,语法行为与传统函数完全不同。 Generator函数有多种理解角度。语法上,首先可以把它理解成,Generator函数是一个状态机,封装了多个内部状态。 执行Generator函数会返回一个遍历器对象,也就是说,Generator函数除了状态机,还有一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历Generator函数内部的每一个状态。 形式上,Generator函数是一个普通函数,但是有两个特征 function关键字与函数名之间有一个星号。 函数体内部使用yield表达式,定义不同的内部状态。 function* helloWorldGenerator() { yield 'hello'; yield 'world'; return 'ending'; } var hw = helloWorldGenerator(); 上面代码定义了一个Generator函数helloWorldGenerator,它内部有两个yield表达式(hello和world),即该函数有三个状态:hello,world和return语句(语句执行)。 然后,Generator函数的调用方法与普通函数一样,也是在函数名后面加上一堆圆括号。不同的是,提哦啊用Generator函数后,函数并不执行,返回的也不是函数运行结果

js-ES6学习笔记-Generator函数

落花浮王杯 提交于 2020-02-13 04:25:14
1、Generator 函数是 ES6 提供的一种异步编程解决方案。形式上,Generator 函数是一个普通函数,但是有两个特征。一是, function 关键字与函数名之间有一个星号;二是,函数体内部使用 yield 语句,定义不同的内部状态。 2、Generator函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用Generator函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是上一章介绍的遍历器对象(Iterator Object)。 3、必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用 next 方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个 yield 语句(或 return 语句)为止。换言之,Generator函数是分段执行的, yield 语句是暂停执行的标记,而 next 方法可以恢复执行。 4、总结一下,调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针。以后,每次调用遍历器对象的 next 方法,就会返回一个有着 value 和 done 两个属性的对象。 value 属性表示当前的内部状态的值,是 yield 语句后面那个表达式的值; done 属性是一个布尔值,表示是否遍历结束。 5、一个函数里面