分析Vue.js组件中的data为何是函数类型而非对象类型 引言 正文 一、Vue.js中data的使用 二、data为对象类型 三、data为函数 结束语 引言 要理解本篇文章,必须具备JavaScript...我们先来了解一下什么是组件化思想,我们一般会在一个页面创建Vue实例,并以该页面作为主文件,然后将其他页面作为该文件的子文件(组件),如图 ?...这是因为这两个实例对象在创建时,是先获得了一个函数,将该函数的返回值作为了自己属性data的值,并且这两个实例对象中data的值在栈中对应的堆中的地址也不一样,所以他们不会互相影响。...因为我们刚开始定义了构造函数Vue时,给他内部的data设置了一个值,该值为对象类型,对象类型在js中称为引用数据类型,在栈中是存储着一个指向内存中该对象的堆中的地址。...此时的情况用图这样表示: ? 结束语 所以讲了那么多,还是一个概念,引用数据类型的表现形式,如果还是有小伙伴不懂的,一定要翻到引言部分,点击链接去看一下这个概念,否则很难理解本篇文章。
前面介绍关键概念的时候提到了 Node类型,里面有个属性叫做 next,它就是为了这种链表设计的,如下图所示。...而 node3.next = null,则说明这是链表的尾巴。...当有新元素准备插入到链表的时候,采用的是尾插法,而不是头插法了,JDK 1.7 的版本采用的是头插法,但是头插法有个问题,就是在两个线程执行 resize() 扩容的时候,很可能造成环形链表,导致 get...使用红黑树是出于性能方面的考虑,红黑树的查找速度要优于链表。那为什么不是一开始就直接生成红黑树,而是链表长度大于 8 之后才升级成树呢?...单节点类型: 直接将当前桶元素替换为被删除 node.next ,其实就是 null。 链表类型: 如果是链表类型,就将被删除 node 的前一个节点的 next 属性设置为 node.next。
value; Node next; Node(int hash, K key, V value, Node next) { this.hash =...对“<<” 有点模糊,当了解“<<”的用法之后,又有一个问题; int类型不是4个字节共32位吗,为什么不是 1[] resize() { Node[] oldTab = table; //定义了一个临时Node类型的数组 int oldCap = (oldTab
C# 是一个类型安全的语言,类型安全允许编译器(可信赖地)捕获潜在的错误,而不是在程序运行时才发现(不可信赖地,往往发生在你将产品出售了以后!)。...这个类还包括一个方法,Append,这个方法接受一个Node类型的参数,我们将把传递进来的Node添加到列表中的最后位置。这过程是这样的:首先检测当前Node的next字段,看它是不是null。...如果当前Node的next字段不是null,说明当前node不是链表中的最后一个node。...通过使用T作为未知类型,next字段(下一个结点的引用)必须被声明为T类型的Node(意思是说接受一个T类型的泛型化Node)。...LinkedList 类现在接受一个 T类型的Node,而不是一个简单的Node作为头结点。
这里其实有一个很细小的知识点,在很多Java面试时被提及,就是 为什么采用位运算而不是直接进行取余操作(符号:%)。...首先,我们先来解释一下为什么需要进行这一步的操作,在上面我们提到哈希值其实是一个int类型,4字节,范围从-2147483648 到 2147483648,这里足足有40亿个映射空间,经过右移和异或操作后...这显然是不现实的,而又因为HashMap的初始数组长度位16,所以要进行一定的操作,让最终的结果值在0~15之间。 那么好!现在又有个问题:为什么要用与运算,而不是%呢?...,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。...loTail.next = e; // 如果低位链表已经有结点,将该元素加入低位链表的尾部 loTail = e; // 更新低位链表的尾结点
但是作为一个可以承载各种类型数据的链表,还需要链表使用者提供一些处理节点中数据的能力。因为这些数据可能是用户自定义的,所以像复制、删除、对比等操作都需要用户来告诉框架。...unsigned long len; } list; 至于链表结构中为什么要存链表长度字段len,我觉得从必要性上来说是没有必要的。...有len字段的一个优点是不用每次计算链表长度时都要做一次遍历操作,缺点便是导出需要维护这个变量。 创建和释放链表 链表创建的过程比较简单。...,创建链表时没有设定链表类型——没有设置复制、释放、对比等方法的指针。...头部和尾部新增都很简单,只是需要考虑一下新增之前链表是不是空的。
——单链表 单链表的基本结构 这种链表为什么被称作单链表呢?...,也可以作为监视哨,或用于存放线性表的长度等附加信息 指针域中存放首元结点的地址 首元结点:存储第一个元素的节点 为什么要附设一个头结点 我们来解释一下: 链表如果为空的情况下,如果单链表没有头结点,那么头指针就会指向...,增加了分支,代码不够简洁 总结:头结点的存在使得空链表与非空链表处理一致,也方便对链表首元结点前结点的插入或删除操作 单链表的类型定义 线性表的抽象数据类型定义 我们在给出单链表的定义之前我们还是需要先引入我们线性表的抽象数据类型定义...} }; //单链表的头指针 Node *head; //单链表的尾指针 Node *tail; //单链表的当前长度 int curLength...尾插法创建单链表 看完了头插法,但是感觉这样的顺序与我们一贯的思维总是有一点别扭,而尾插法则是一种,逻辑顺序与我们一致的创建方法 还是看一下图 ?
1 概述 在Linux内核中,对于数据的管理,提供了2种类型的双向链表:一种是使用list_head结构体构成的环形双向链表;另一种是使用hlist_head和hlist_node2个结构体构成的具有表头的链型双向链表...而在(b)图中,next类似,指向下一个hlist_node结构的地址,而pprev指向前一个hlist_node的next指针。这是为什么呢?我们将在第3章中讨论。...内核为什么设计这么2个双向链表呢?使用它们有什么好处?它们的使用场景分别是什么呢?...有了这个指针,我们就可以访问其任何成员了。 2.8 遍历链表 list_for_each遍历一个链表。...pprev指向前一个节点的next指针. 现在疑问来了:为什么pprev不是prev也就是一个指针,用于简单的指向list的前一个指针呢?
前面博客我们在讲解数组中,知道数组作为数据存储结构有一定的缺陷。...而链表也是一种使用广泛的通用数据结构,它也可以用来作为实现栈、队列等数据结构的基础,基本上除非需要频繁的通过下标来随机访问各个数据,否则很多使用数组的地方都可以用链表来代替。 ...而插入一个节点,对于单向链表,我们只提供在链表头插入,只需要将当前插入的节点设置为头节点,next指向原头节点即可。删除一个节点,我们将该节点的上一个节点的next指向该节点的下一个节点。 ? ...数据类型允许的操作是它本身不可分离的部分,理解类型包括理解什么样的操作可以应用在该类型上。 那么当年设计计算机语言的人,为什么会考虑到数据类型? ...而每个节点对象通常包含数据部分data,以及对上一个节点的引用prev和下一个节点的引用next,只有下一个节点的引用称为单向链表,两个都有的称为双向链表。
table数组长度永远为2的幂次方 总所周知,HashMap数组长度永远为2的幂次方(指的是table数组的大小),那你有想过为什么吗?...如果不对它减1而直接操作,将得到答案10000,即16。显然不是结果。减1后二进制为111,再进行操作则会得到原来的数值1000,即8。通过一系列位运算大大提高效率。...因为当table数组容量比较小时,键值对节点 hash 的碰撞率可能会比较高,进而导致链表长度较长。这个时候应该优先扩容,而不是立马树化。...,若是则返回该节点 若不是则判断节点的类型,如果是红黑树的话,则调用红黑树的方法去查找元素 如果是链表类型,则遍历链表调用equals方法去查找元素 HashMap的查找是非常快的,要查找一个元素首先得知道...这就解释了为什么遍历和插入的顺序不一致,不懂的同学请看下图: equasl和hashcode 我在面试中就被问到过HashMap的key有什么限制吗?
table数组长度永远为2的幂次方 总所周知,HashMap数组长度永远为2的幂次方(指的是table数组的大小),那你有想过为什么吗?...如果不对它减1而直接操作,将得到答案10000,即16。显然不是结果。减1后二进制为111,再进行操作则会得到原来的数值1000,即8。通过一系列位运算大大提高效率。...因为当table数组容量比较小时,键值对节点 hash 的碰撞率可能会比较高,进而导致链表长度较长。这个时候应该优先扩容,而不是立马树化。...,若是则返回该节点 若不是则判断节点的类型,如果是红黑树的话,则调用红黑树的方法去查找元素 如果是链表类型,则遍历链表调用equals方法去查找元素 HashMap的查找是非常快的,要查找一个元素首先得知道...这就解释了为什么遍历和插入的顺序不一致,不懂的同学请看下图: ? equasl和hashcode 我在面试中就被问到过HashMap的key有什么限制吗?
有序数组 无序链表 (二叉树的实现方案将在下一篇文章介绍) 【注意】 为了让代码尽可能简单, 我将字典的Key和Value的值也设置为int类型,而不是对象, 所以在下面代码中, 处理“操作失败”的情况的时候...,是返回 -1 而不是返回 null 。...所以代码默认不能选择 -1作为 Key或者Value (在实际场景中,我们会将int类型的Key替换为实现Compare接口的类的对象,同时将“失败”时的返回值从-1设为null,这时是没有这个问题的)...“静态查找表” 若在查找过程中同时还进行了3,4操作, 这样的查找表被称为“动态查找表” 有序数组实现字典 有序数组实现字典思路 字典,有最关键的两个类型的值: Key和Value。...节点对象有三个实例变量: key,value和next, key和value分别用来存储字典的键和值, 而next用于建立节点和节点间的引用联系。
table 数组长度永远为 2 的幂次方 总所周知,HashMap 数组长度永远为 2 的幂次方(指的是 table 数组的大小),那你有想过为什么吗?...如果不对它减1而直接操作,将得到答案 10000,即 16。显然不是结果。减 1 后二进制为 111,再进行操作则会得到原来的数值 1000,即 8。通过一系列位运算大大提高效率。...接着需要判断如果不是第一次初始化,那么扩容之后,要重新计算键值对的位置,并把它们移动到合适的位置上去,如果节点是红黑树类型的话则需要进行红黑树的拆分。...因为当 table 数组容量比较小时,键值对节点 hash 的碰撞率可能会比较高,进而导致链表长度较长。这个时候应该优先扩容,而不是立马树化。...,int 有 32 位,右移 16 位就能让低 16 位和高 16 位进行异或,也是为了增加 hash 值的随机性。
首先,我们把双链表的节点类写出来,为了简化,key 和 val 都认为是 int 类型: class Node { public int key, val; public Node next...Node 类型构建一个双链表,实现几个 LRU 算法必须的 API: class DoubleList { // 头尾虚节点 private Node head, tail;...删除一个节点不光要得到该节点本身的指针,也需要操作其前驱节点的指针,而双向链表才能支持直接查找前驱,保证操作的时间复杂度 O(1)。...有了双向链表的实现,我们只需要在 LRU 算法中把它和哈希表结合起来即可,先搭出代码框架: class LRUCache { // key -> Node(key, val) private...(deletedKey); } 这里就能回答之前的问答题「为什么要在链表中同时存储 key 和 val,而不是只存储 val」,注意 removeLeastRecently 函数中,我们需要用 deletedNode
与数组一样,链表是一种线性数据结构。与数组不同,链表元素不存储在连续的位置;元素使用指针链接。 为什么使用链表? 数组可用于存储类似类型的线性数据,但数组有以下限制。...在 Java 或 C# 中,LinkedList 可以表示为一个类,而一个 Node 可以表示为一个单独的类。LinkedList 类包含一个 Node 类类型的引用。...第一个简单链表 1.C //一个链表节点 struct Node { int data; struct Node* next; }; 2.C++ class Node { public: int...默认为 null) Node head; class Node { int data; Node next; // 创建新节点的构造函数 Node(int d) { data = d...我们有指向这三个块的指针作为头部, 第二个和第三个 head second third | | | | | | +---+-----+ +----+--
一、list底层框架 list的底层是一个带头双向循环链表. (1) 节点类 因为list中节点可能存储各种类型的值,所以这里使用了一个模板参数T....//存储数据 }; (2) 迭代器类 很多小伙伴会疑问,为什么一个迭代器类却使用了三个模板参数,是不是有些多余呢?...Ref operator*() { return _node->_val;//获取该结点的数据 } (2) -> 上面链表中的数据是简单的类型int Ptr operator->().../ 在pos位置前插入值为val的节点 iterator insert(iterator pos, const T& val) { //pos.node 而不是pos->node..._size); } 结语 看完这篇文章,相信大家对list有了更加深层的理解,对于list的迭代器,它并不像前面的string和vector那种原生指针,而是封装成了类,使得链表的迭代器也可以执行++
Node 类型的数组。...这个 Node 节点可能是链表节点,也可能是红黑树节点。说到 Node 节点,我们有必要详细说说 Node 节点的类关系图。...如果此时,oldThr > 0,表示有设置了初始值 // 那么将初始值 oldThr 作为新的容量大小。...这时候我们有两种选择,一种是扩容,让哈希碰撞率低一些。另一种是树化,提高查询效率。 如果我们采用扩容,那么我们需要做的就是做一次链表数据的复制。而如果我们采用树化,那么我们需要将链表转化成红黑树。...这个时候我们有许多树化的红黑树,在扩容之时,我们需要将许多的红黑树拆分成链表,这是一个挺大的成本。而如果我们在容量小的时候就进行扩容,那么需要树化的链表就越少,我们扩容的成本也就越低。
首先,我们把双链表的节点类写出来,为了简化,key 和 val 都认为是 int 类型: class Node { public int key, val; public Node next...// 删除链表中的 x 节点(x 一定存在) // 由于是双链表且给的是目标 Node 节点,时间 O(1) public void remove(Node x) { x.prev.next...int size() { return size; } } 到这里就能回答刚才「为什么必须要用双向链表」的问题了,因为我们需要删除操作。...有了双向链表的实现,我们只需要在 LRU 算法中把它和哈希表结合起来即可,先搭出代码框架: class LRUCache { // key -> Node(key, val) private...(deletedKey); } 这里就能回答之前的问答题「为什么要在链表中同时存储 key 和 val,而不是只存储 val」,注意 removeLeastRecently 函数中,我们需要用 deletedNode
那我们接下来思考一个问题:算法库里面不是已经有sort了吗,为什么链表自己还要提供一个sort? 最主要的原因是算法库里的排序list就用不了。 我们发现报了一堆错怎么,回事呢?...是不是不行啊,因为双向既要支持++还要支持- -,而单向是不是只能++啊: 但是我们传随机可以吗? 是不是可以啊,因为随机是支持++和- -的。...是不是不需要啊,因为它不需要去释放里面指针指向的结点的空间。 那为什么不需要释放啊? ,它里面虽然有结点的指针,但是它指向的结点属于谁,是不是属于list啊,那结点的释放应该是谁的事情?...const迭代器 假如现在我们要写一个打印链表的函数: 然后我们调用该函数: 发现报错了,为什么,是不是又是权限放大的问题啊? 怎么解决?...->_next; return *this; } self operator++(int) { self tmp(*this); _node = _node->_next;
,没错,数据的载体,是数组,并且数组的类型是Node,节点的意思 //真正存放key value的地方 transient Node[] table; Node代表是类型,[]代表是数组,K...,相当于乘2 为什么容量都是2的倍数 核心还是为了性能,在读跟取的时候,经常需要根据key的hash值,快速定位到数组对应的position,而当数组的长度是2的倍数的时候,就可以用位运算快速的计算出来...,不代表找到的node就是我们要的node,因为不同的key,有可能hash值是相同的,所以引申了下面的问题 碰到hash冲突怎么办 hashmap有两种处理冲突的方式,一是用链表来存储,存储的时候,...也是新建一个node,跟当前的node组成链表,不断有新的冲突,就不断的往这个链表后面添加 //一个无限循环,由内部条件控制退出循环 for (int binCount = 0; ; ++binCount...,不过看上面代码也知道,当链表比较长的时候,就不适合采用链表来存储,会被转成红黑树来存储; 从性能角度考虑,链表只能从头开始往后检索,算法的时间复杂度是O(n),而红黑树的时间复杂度是O(log n),
领取专属 10元无门槛券
手把手带您无忧上云