链表

每日一题

夙愿已清 提交于 2020-02-18 21:56:59
分割链表 编写程序以 x 为基准分割链表,使得所有小于 x 的节点排在大于或等于 x 的 节点之前。如果链表中包含 x,x 只需出现在小于 x 的元素之前(如下所示)。分割元素 x 只需处于“右半部分”即可,其不需要被置于左右两部分之间。 示例: 输入: head = 3->5->8->5->10->2->1, x = 5 输出: 3->1->2->10->5->5->8 链接: https://leetcode-cn.com/problems/partition-list-lcci/ //思路:双指针 //第一个指针找到第一个大于x的值 //第二个指针在第一个指针后面找到第一个小于x的值(如果没有找到则证明已经完全分割完成) //交换两指针的值 public ListNode partition ( ListNode head , int x ) { ListNode behind , front ; behind = front = head ; for ( ; behind != null ; behind = behind . next ) { if ( behind . val >= x ) { for ( front = behind . next ; front != null && front . val >= x ; front = front . next )

Map源码会问哪些面试题

爷,独闯天下 提交于 2020-02-18 15:20:34
1 Map 整体数据结构类问题 1.1 说一说 HashMap 底层数据结构 答:HashMap 底层是数组 + 链表 + 红黑树的数据结构,数组的主要作用是方便快速查找,时间复杂度是 O(1),默认大小是 16,数组的下标索引是通过 key 的 hashcode 计算出来的,数组元素叫做 Node,当多个 key 的 hashcode 一致,但 key 值不同时,单个 Node 就会转化成链表,链表的查询复杂度是 O(n),当链表的长度大于等于 8 并且数组的大小超过 64 时,链表就会转化成红黑树,红黑树的查询复杂度是 O(log(n)),简单来说,最坏的查询次数相当于红黑树的最大深度。 1.2 HashMap、TreeMap、LinkedHashMap 三者有啥相同点,有啥不同点? 答:相同点: 三者在特定的情况下,都会使用红黑树; 底层的 hash 算法相同; 在迭代的过程中,如果 Map 的数据结构被改动,都会报 ConcurrentModificationException 的错误。 不同点: HashMap 数据结构以数组为主,查询非常快,TreeMap 数据结构以红黑树为主,利用了红黑树左小右大的特点,可以实现 key 的排序,LinkedHashMap 在 HashMap 的基础上增加了链表的结构,实现了插入顺序访问和最少访问删除两种策略; 由于三种 Map

双向链表&LRU缓存淘汰算法

三世轮回 提交于 2020-02-18 15:19:55
单链表的尾结点指针指向null,表示这就是最后的结点了。 循环链表是一种特殊的单链表,和单链表区别于首尾相接,其优点是从链尾到链头比较方便,适合于数据具有环型结构。 双向链表的每个数据结点都包含有三个域值(pre,data,next)。从双向链表中的任意结点开始,都能够很方便地访问到它的前驱结点和后继结点。特点:1.存储同样多的数据,要占用更多的内存。2.插入和删除需同时维护 next 和 pre 两个引用。3.支持双向遍历,这是双向链表操作的灵活性。 双向链表 1.添加元素。 与单向链表相对比双向链表可以在 O(1) 时间复杂度搞定,而单向链表需要 O(n) 的时间复杂度。 头插法: 将链表的左边称为链表头部,右边称为链表尾部。头插法是将右边固定,每次新增的元素都在左边头部增加。 尾插法: 将链表的左边称为链表头部,右边称为链表尾部。尾插法是将左边固定,每次新增都在链表的右边最尾部。 2.查询元素 双向链表的灵活性: 知道链表中的一个元素的下标就可以向左或者向右开始遍历查找需要的元素 。因此对于一个有序链表,双向链表的按值查询的效率比单链表高一些。因为,我们可以记录上次查找的位置 p,每次查询时,根据要查找的值与 p 的大小关系,决定是往前还是往后查找,所以平均只需要查找一半的数据。 3.删除元素( 单链表删除操作需要 O(n) 的时间复杂度,而双向链表只需要在 O(1)

链表练习

橙三吉。 提交于 2020-02-18 14:16:41
删除链表中等于给定值 val 的所有节点 public ListNode removeElements ( ListNode head , int val ) { // 1. 链表为空的情况 if ( head == null ) { return null ; } // 2. 处理非头结点 ListNode prev = head ; ListNode node = head . next ; while ( node != null ) { if ( node . val == val ) { prev . next = node . next ; node = prev . next ; } else { prev = node ; node = node . next ; } } // 3. 处理头结点 if ( head . val == val ) { head = head . next ; } return head ; } 反转一个单链表 public ListNode reverseList ( ListNode head ) { // 1. 判定空链表的情况 if ( head == null ) { return null ; } // 2. 只有一个元素 if ( head . next == null ) { return head ; }

深入理解JDK8 HashMap

岁酱吖の 提交于 2020-02-18 08:36:18
笔者在上一篇文章《 深入理解JDK7 HashMap 》中详细解析了HashMap在JDK7中的实现原理,主要是围绕其put、get、resize、transfer等方法,本文将继续解析HashMap在JDK8中的具体实现,首先也将从put、get、resize等方法出发,着重解析HashMap在JDK7和JDK8中的具体区别,最后回答并解析一些常见的HashMap问题。在阅读本篇文章之前,建议阅读上一篇文章作为基础。 一、HashMap在JDK8中的结构 上一篇文章提到,HashMap在JDK7或者JDK8中采用的基本存储结构都是 数组+链表 形式,可能有人会提出疑问,HashMap在JDK8中不是 数组+链表+红黑树 吗?本文的回答 是 。至于为什么JDK8在一定条件下将链表转换为红黑树,我相信很多人都会回答: 为了提高查询效率 。基本答案可以说是这样的,JDK7中的HashMap对着Entry节点增多,哈希碰撞的概率在慢慢变大,这就直接导致哈希表中的单链表越来越长,这就大大降低了HashMap的查询能力,且时间复杂度可能会退化到O(n)。针对这种情况,JDK8做出了优化,就是在一定的条件下,链表会被转换为红黑树,提升查询效率。 HashMap在JDK8中基本结构示意图如下所示: 在上面的示意图可以看出,与JDK7的最大区别就是哈希表中不仅有链表,还有可能存在红黑树这种结构

C# 实现单链表

天涯浪子 提交于 2020-02-18 06:18:00
节点类: using System; using System.Collections.Generic; using System.Text; namespace DateStructrues.Lists.Node { /// <summary> /// 节点类。 /// </summary> /// <typeparam name="T"></typeparam> public class DNode<T> { #region Fields // //数据域 // T _data; // //地址域(下一个) // DNode<T> _next; // //地址域(上一个) // DNode<T> _prev; #endregion #region Constructor /// <summary> /// 构造器 /// </summary> /// <param name="value"></param> public DNode(T value) { _data = value; } /// <summary> /// 构造器 /// </summary> /// <param name="value"></param> /// <param name="prev"></param> /// <param name="next"></param> public DNode

剑指offerNo15.反转链表(Java)

断了今生、忘了曾经 提交于 2020-02-18 04:24:47
题目描述: 输入一个链表,反转链表后,输出新链表的表头。 思路:用两个指针,其中一个指针next用来保存head.next之后的节点, 然后用prev指针指向当前节点的前一个节点,将当前节点的next指向前一个节点。 最后将当前节点和当前节点的前一个节点进行后移 代码: package offer; public class TestNo15 { static class ListNode{ int val; ListNode next; ListNode(int x){ val = x; } public String toString(){ if(this.next==null){ return String.valueOf(this.val); }else{ return this.val +"->" + this.next.toString(); } } } public static void main(String[] args) { ListNode head = new ListNode(0); ListNode newHead = head; for(int i= 1;i<5;i++){ newHead.next = new ListNode(i); newHead = newHead.next; } System.out.println(new TestNo15

collection(list,set,map)、HashMap

断了今生、忘了曾经 提交于 2020-02-18 02:53:39
collection里面有什么子类?(list和set是实现了collection接口的。)   List: 1.可以允许重复的对象(可重复,有序集合)。 2.可以插入多个null元素。 3.常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。 ———————————————— Set: 1.不允许重复对象(不可重复,无序集合)。 2 只允许一个 null 元素 3.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序集合。而且可以重复。 ———————————————— Map: 1.Map不是collection的子接口或者实现类。Map是一个接口。 2.不允许重复元素。 3. Map 里你可以拥有随意个 null 值但只能有一个 null (key)键。 4. Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable

leetcode——链表篇

老子叫甜甜 提交于 2020-02-18 02:02:57
链表: 链表和 链表右移动k位 翻转链表 两两交换链表节点 链表根据X分区: 删除链表重复元素: 最多出现两次的数组 链表和: 给出两个非空的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 示例: 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807 public static ListNode addTwoNumber(ListNode l1, ListNode l2) { ListNode dumyHead = new ListNode(0); ListNode p = l1, q = l2, curr = dumyHead; int carry = 0; // 表示是否需要进位(只有连个值:0跟1) while(p != null || q != null) { int x = (p != null ) ? p.val : 0; // 需要考虑位数不同的数字相加 int y = (q != null ) ? q.val : 0; int sum = carry + x + y; carry = sum /

HashMap 实现原理及源码分析

偶尔善良 提交于 2020-02-18 00:43:39
HashMap是JDK中非常重要的容器,采用 数组 + 链表 的方式实现,理想情况下能支持 O(1) 时间复杂度的增删改查操作。本文将由浅入深地讲解哈希表的实现原理,并对HashMap的部分源码进行分析。 1. 从数组说起 数组应该是我们最先学习的数据结构,它是内存中一块连续的存储单元,因此计算机可以根据数组起始地址、元素长度和下标,计算出我们要访问的元素的地址,时间复杂度为 O(1) 。 以下代码定义了一个简单的 Student 类,假如我们要存储 20 个 Student 对象,我们希望能够在 O(1) 时间复杂度内,根据 studentID 找到相应的对象。 public class Student { public int studentID; public String name; public Student(int studentID, String name) { this.studentID = studentID; this.name = name; } } 如果我们要存储的 20 个 Student 对象的 studentID 刚好就是从 0 到 19,我们自然可以新建一个长度为 20 的 Student 数组 students,然后将对象的 studentID 作为数组下标,放到对应的 slot 里面,如下图所示。这样的话,如果我们想找 studentID