链表

Leetcode[141] 环形链表

China☆狼群 提交于 2020-02-07 01:20:17
题目描述 给定一个链表,判断链表中是否有环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 示例 1: 输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。 示例 2: 输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。 示例 3: 输入:head = [1], pos = -1 输出:false 解释:链表中没有环。 题解思路 双指针法:从头节点开始,建立两个快慢指针 quick 和 slow,快指针每次走两步 quick = quick -> next -> next,慢指针每次走一步 slow = slow -> next,同时遍历链表,当快慢指针相遇时,说明该链表有环,否则说明链表中无环。 注意:快慢指针遍历链表时,终止条件为:quick != NULL && quick -> next != NULL AC代码 /** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ bool hasCycle

C++二叉搜索树与双向链表(剑指Offer精简版)

戏子无情 提交于 2020-02-07 00:52:20
题目:输入一棵二叉搜索树,将该二叉搜素树转换成一个排序的双向链表。 二叉树节点定义如下: struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } }; 解题思路: 由于通过中序排序可以转化为双向链表,因此,通过中序遍历的方法(左根右)的递归方法可以解决问题,解决完之后,pList节点指向双向链表的尾结点,pList节点需要通过遍历,返回到头节点,同样,我们也可以通过逆向中序遍历的方法之间完成,代码如下: class Solution { public: TreeNode* Convert(TreeNode* pRootOfTree) { TreeNode* pList=nullptr;//双向链表的头节点 Convert(pRootOfTree,pList); return pList; } void Convert(TreeNode* pRootOfTree,TreeNode*& pList) { if(pRootOfTree==nullptr)//递归的出口 return; if(pRootOfTree->right!=nullptr)//递归处理右子树 Convert

深入理解JDK中的Reference原理和源码实现

故事扮演 提交于 2020-02-07 00:39:24
前提 这篇文章主要基于JDK11的源码和最近翻看的《深入理解Java虚拟机-2nd》一书的部分内容,对JDK11中的 Reference (引用)做一些总结。值得注意的是,通过笔者对比一下JDK11和JDK8对于 java.lang.ref 包的相关实现,发现代码变化比较大, 因此本文的源码分析可能并不适合于JDK11之外的JDK版本 。 Reference的简介和分类 在JDK1.2之前,Java中的引用的定义是十分传统的:如果reference类型的数据中存储的数值代表的是另一块内存的起始地址,就称这块内存代表着一个引用。在这种定义之下,一个对象只有被引用和没有被引用两种状态。 实际上,我们更希望存在这样的一类对象:当内存空间还足够的时候,这些对象能够保留在内存空间中;如果当内存空间在进行了垃圾收集之后还是非常紧张,则可以抛弃这些对象。基于这种特性,可以满足很多系统的缓存功能的使用场景。 java.lang.ref 包是JDK1.2引入的,包结构和类分布如下: - java.lang.ref - Cleaner.class - Finalizer.class - FinalizerHistogram.class - FinalReference.class - PhantomReference.class - Reference.class - ReferenceQueue

数据结构与算法(双向链表)

老子叫甜甜 提交于 2020-02-06 22:13:34
一种更复杂的链表叫“双向链表”或者“双面链表”,每个节点有两个链接,一个指向前一个节点,当此节点为第一个节点时,指向空值;而另一个指向下一个节点,当此节点为最后一个节点时,指向空值。 操作实现 class Node(object): """节点类""" def __init__(self, item): self.elem = item self.prev = None self.next = None class DoubleLinkList(object): """双链表""" def __init__(self, node=None): self._head = node def is_empty(self): return self._head is None def length(self): """链表长度""" #cur游标,用来移动遍历节点 cur = self._head #count记录数量 count = 0 while cur != None: count = count + 1 cur = cur.next return count def travel(self): """遍历整个链表""" #cur游标,用来移动遍历节点 cur = self._head #count记录数量 while cur != None: print(cur.elem,end=

LeetCode --- 142. 环形链表 II

偶尔善良 提交于 2020-02-06 22:06:33
LeetCode链接: 142. 环形链表 II /** * Definition for singly-linked list. * class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ public class Solution { public ListNode detectCycle ( ListNode head ) { ListNode fast = head , slow = head ; while ( true ) { if ( fast == null || fast . next == null ) return null ; fast = fast . next . next ; slow = slow . next ; if ( fast == slow ) break ; } fast = head ; while ( slow != fast ) { slow = slow . next ; fast = fast . next ; } return fast ; } } 来源: CSDN 作者: 玉树临风你卓哥 链接: https://blog.csdn.net/songzhuo1991/article

hashMap关键知识点

☆樱花仙子☆ 提交于 2020-02-06 20:13:10
1、数据结构 jdk1.7是数组加链表,jdk1.8是数组加链表加红黑树(链表太长了查询也慢,所以链表长度超过8时就使用红黑树咯) 2、hashMap的初始化大小 1)不给长度时,默认初始化为16,创建map时尽量给个长度,防止不断扩容影响效率。 2)大小为2的n次幂时,散列得比较均匀,那么查询就比较快 3、hashMap的put原理 1)把key值通过hash函数(hashcode与map长度减一的二进制做与运算,这样得出0到长度减一的下标)计算一个位置index 例如: 初始化长度为8 hashcode为11001 那么下标就为0 0111&11001=0 0001 那么下标就为1 初始化长度为8 hashcode为11111 那么下标就为0 0111&11111=0 0111 那么下标就为7 2)检测index所在位置是否有值,有值得话就比较key值是否相等, 不等的话直接把值接在所在对象的链表的后面,相等的话就覆盖原有的值 4、hashMap的扩容原理 1)当map中的元素个数等于map长度乘以加载因子时,就需要扩容了;扩容到原来长度的两倍 2)扩容使用的是头插法,扩容之后链表的顺序为倒序,这也是导致多线程扩容时出现环路导致线程不安全的原因 5、hashMap的get原理 1)把key值通过hash函数计算一个位置index 6、hashMap的加载因子 1

快慢指针

三世轮回 提交于 2020-02-06 20:00:46
什么是快慢指针 这种模式,有一个非常出门的名字,叫龟兔赛跑。咱们肯定都知道龟兔赛跑啦。但还是再解释一下快慢指针:这种算法的两个指针的在数组上(或是链表上,序列上)的移动速度不一样。还别说,这种方法在解决有环的链表和数组时特别有用。 通过控制指针不同的移动速度(比如在环形链表上),这种算法证明了他们肯定会相遇的。快的一个指针肯定会追上慢的一个(可以想象成跑道上面跑得快的人套圈跑得慢的人)。 咋知道需要用快慢指针模式? 问题需要处理环上的问题,比如环形链表和环形数组 当你需要知道链表的长度或是某个特别位置的信息的时候 那啥时候用快慢指针而不是上面的双指针呢? 有些情形下,咱们不应该用双指针,比如我们在单链表上不能往回移动的时候。一个典型的需要用到快慢指针的模式的是当你需要去判断一个链表是否是回文的时候。 一般情况下,快慢指针出现在链表的频率更高。 快慢指针判断链表有环 快指针fast一次走两步,慢指针slow一次走一步,如果有环的话,它们在环上一定会相遇(值相等),此时就证明有环。所以,如果最终fast == nullptr,那么判断链表无环;如果最终fast == slow,且fast != nullptr,那么链表有环。 快慢指针寻找环入口的原理 第一步:快慢指针从头结点出发。如下图所示。蓝色表示快指针fast,红色表示慢指针slow。 第二步:慢指针slow走到了环入口

牛客 二叉搜索树与双向链表

泄露秘密 提交于 2020-02-06 18:34:30
题目要求: 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。 解题思路: 思路1: 我们知道双向链表中,每个结点有两个指针域,一个指向前一个结点,一个指向后一个结点。而在二叉树中同样也有两个指针域,一个指向左孩子,一个指向右孩子。所以二叉树和双向链表结构上是相似的。又因为二叉搜索树中,左孩子一定小于父节点,右孩子一定能够大于父节点。所以我们可以将原先指向左孩子的指针当做是链表中指向前一个结点的指针,将原先指向右孩子的指针当做是链表中指向后一个结点的指针。如图: 题目要求转换后是有序的双向链表,因为二叉搜索树的中序遍历是有序的,所以采用中序遍历来完成。当遍历到根节点的时候,只需将根和左子树最大的一个结点链接起来,将跟结点和右子树最小的一个结点链接起来即可。如图: 按照中序遍历递归,当遍历到根结点的时候,说明此事根结点的左子树已经是有序的双向链表了,并且此时链表尾部的值为左子树的最大值。我们将其与根结点链接起来,此时根结点变成了尾部,我们知道根结点后面的节点是右子树最小的结点,将其与根结点链接起来,再继续递归即可解决问题。 代码: class solution1 { TreeNode * head = nullptr ; //进行链接的头 TreeNode * realhead = nullptr ; /

链表的C++实现

▼魔方 西西 提交于 2020-02-06 18:17:18
参考用书《数据结构》(秦锋,汤亚玲主编) 贴下代码: # include <iostream> # include <string> using namespace std ; class Node { public : string data ; Node * next ; Node ( ) { next = NULL ; } } ; class Link { public : Node * head ; //头指针 Link ( ) //构造函数 { head = NULL ; } ~ Link ( ) { //析构函数 DeleteAll ( ) ; } void Initiate ( ) ; //初始化 void DeleteAll ( ) ; //删除所有节点 void HeadCreate ( int n ) ; //头插法建表 void TrailCreate ( int n ) ; //尾插法建表 void HeadCreateWithHead ( int n ) ; //建立带表头的链表(从头) void TrailCreateWithTrail ( int n ) ; //建立带表头的链表(从尾) int Length ( ) ; //链表长度 Node * Locatex ( string data ) ; //查找值为x的数据元素 Node *

HashMap源码分析

一个人想着一个人 提交于 2020-02-06 17:12:08
概述 HashMap实现了Map<K, V>接口,通过键-值(key-value)的方式存取数据。内部的数据结构是数组+链表(或者Tree),插入时通过key的hash值,映射((n - 1) & hash,其中n为数组的长度)到数组中的位置,如果hash值重复,则在链表的末端插入(当一个链表中的数据大于等于8个时,就将链表转变为Tree),而当数组达到一定值时,会resize,重新创建一个数组,大小是之前的两倍;取出时,也是通过key的hash值,映射到数组的位置,如果刚好是第一个,则返回,否则一直查找到key相等的value并返回,如果还是没找到则分会null。 本文的目标是带着学习的态度,查看HashMap的源码,从put,get,resize三个方法分析它的内部实现。 HashMap数据结构 HashMap继承自AbstractMap<K,V>,实现了Map<K, V>接口(AbstractMap<K,V>也实现了这个接口,为什么没有冲突呢?): Map接口有一个Entry接口,HashMap中内部类Node实现了Entry接口,数据就存放在: Node < K , V > [ ] table ; HashMap内部定义了几个重要参数: // 加载因子默认是0.75,取值越小,hash冲突概率越低,插入和查找速度愈快,但是占用的空间更多 final float