链表

集合框架系列 Map(十):HashMap

柔情痞子 提交于 2020-03-18 18:17:13
目录 1 概述 2 原理 3 源码分析  3.1 构造方法   3.1.1 构造方法分析   3.1.2 初始容量、负载因子、阈值  3.2 查找  3.3 遍历  3.4 插入   3.4.1 插入逻辑分析   3.4.2 扩容机制   3.4.3 链表树化、红黑树链化与拆分  3.5 删除  3.6 其他细节  3.7 总结 1. 概述 本篇文章我们来聊聊大家日常开发中常用的一个集合类 - HashMap 。HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现。HashMap 允许 null 键和 null 值,在计算哈键的哈希值时,null 键哈希值为 0。HashMap 并不保证键值对的顺序,这意味着在进行某些操作后,键值对的顺序可能会发生变化。另外,需要注意的是,HashMap 是非线程安全类,在多线程环境下可能会存在问题。 在本篇文章中,我将会对 HashMap 中常用方法、重要属性及相关方法进行分析。需要说明的是,HashMap 源码中可分析的点很多,本文很难一一覆盖,请见谅。 2. 原理 上一节说到 HashMap 底层是基于散列算法实现,散列算法分为散列再探测和拉链式。HashMap 则使用了拉链式的散列算法,并在 JDK 1.8 中引入了红黑树优化过长的链表。数据结构示意图如下: 对于拉链式的散列算法,其数据结构是由数组和链表(或树形结构)组成

C++用数组和链表分别实现Stack

◇◆丶佛笑我妖孽 提交于 2020-03-18 14:07:41
C++用数组和链表分别实现Stack   C++ 学习有段时间了,感觉还是有很多不足啊,今天自己用数组和链表分别实现Stack,当然STL中的Stack肯定不是这么简单,你不妨看一下,说不定有收获呢,若发现有问题,请指正,毕竟对于C++我还是新手。 数组版 // typename可以表示任何类型,而class只能表示类 template < typename T,typename container > class stack { public : // 栈是否为空 bool empty( ) const { return index == 0 ; } // 出栈 void pop( ) { if (empty()) { throw new exception( " 栈中没有数据 " ); } arr[index - 1 ] = 0 ; -- index; } // 出栈,如果默认数组未满继续添加数据,如果已满,重新分配一个两倍的数组, // 把默认数组中的数据拷贝过来,释放默认数组,将指针指向新数组 void push( const T & val) { if (index <= capacity - 1 ) { arr[index ++ ] = val; } else { capacity <<= 1 ; // capacity对应的二进制数左移一位 int * tmp =

数据结构

强颜欢笑 提交于 2020-03-18 14:06:20
1. 几个景点算法: 1.  修路问题:最小生成树(加权值)+ 普利姆 2. 最短路径:图+弗洛伊德算法 3. 汉诺塔: 分支的算法 4. 八皇后:回朔法、 5. 丢手帕 : 约瑟夫问题 2. 线性结构 与非线性结构 1.线性结构 :数据元素之间存在一对一的线性关系 顺序存储结构 , 链式存储结构 (数组,队列,链表和栈) 2 . 非线性结构:(二维数组,多维数组,广义表,树结构,图结构) 3. 稀疏数组 因为该数组中记录了很多值是默认值0,记录了很多没有意义的数据 -》 稀疏数组 代码实现原始二维数组与稀疏数组之间的转化 import org.junit.Test; public class XiShuJuZhen { //创建一个原始的二维数组 11*11 @Test public void testArray() { int[][] charArray = new int[11][11]; //0表示没有棋子,1 表示黑子 2表示蓝子 charArray[1][2] = 1; charArray[2][3] = 2; charArray[4][5] = 2; System.out.println("输出原始的二维数组"); for (int[] is : charArray) { for (int is2 : is) { System.out.print("\t"+is2);

Oracle中读取数据一些原理研究

旧城冷巷雨未停 提交于 2020-03-18 11:55:02
文章很多摘录了 http://blog.163.com/liaoxiangui@126/blog/static/7956964020131069843572/ 同时基于这篇文章的基础上,补充一些学习要点,如有问题,希望指出探讨. 1 ORACLE体系结构 下图描述了oracle的体系结构。SGA(system global area)是各个进程共享的内存块,Buffer cache用来缓存数据文件的数据块(block)。 2 如何在data buffer中查找数据块 data buffer存在的意义就是为了在内存中进行高速的数据查找和更新,尽量减少磁盘的IO操作, Buffer Cache中存在一个Hash Bucket结构,将数据库中已经读取的数据块放到里面,在从数据库文件中读取到一个数据块后,Oracle会根据这个数据块的文件编号,段编号,数据块号组合到一起通过一个内部的hash算法运算后,会放到不同的hash bucket中,每个Hash Bucket都有一个Hash chain list,保留Buffer Header中的信息,然后通过这个list,把相同hash值的Buffer串起来.结构如图: 为保护这个结构不受同步更新的破坏,Oracle设计了一个CBC latch的锁结构(Cache Buffers Chains),一个latch保护32的桶(Bucket)

Leetcode(二)两数相加

无人久伴 提交于 2020-03-18 11:28:30
两数相加 题目描述 给出两个非空的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 示例 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807 思路: 解决这个问题我并没有想到什么很便捷的方法,就是从两个链表的表头逐位累加,并注意判断是否进位值。 代码如下: public static ListNode towNumbers(ListNode l1, ListNode l2){ ListNode node=new ListNode(0); ListNode temp=node; int sum=0; int carry = 0; while(l1!=null||l2!=null){ int x=l1==null?0:l1.val; int y=l2==null?0:l2.val; sum=x+y+carry; carry=sum/10; temp.next=new ListNode(sum%10); temp=temp.next; l1=l1==null?null:l1.next; l2=l2==null

Kernel数据结构移植(list和rbtree)

浪子不回头ぞ 提交于 2020-03-18 07:15:58
主要移植了内核中的 list,rbtree。使得这2个数据结构在用户态程序中也能使用。 同时用 cpputest 对移植后的代码进行了测试。(测试代码其实也是使用这2个数据结构的方法) 内核代码的如下文件:(内核版本 v3.2 debian 7.5源码) include/linux/list.h (删除了 hlist 相关内容) include/linux/rbtree.h lib/rbtree.c 对上面的代码进行了一些简化,只留了常用的函数。同时删除了其中和内核相关的部分。 主要内容: list 介绍 (循环双向链表) rbtree 介绍 1. list 介绍 (循环双向链表) 1.1 简介 Linux中的链表用法与一般数据结构书中介绍的用法有些不一样。 Linux内核中,为了保证链表的通用性,将链表的节点结构单独抽取了出来,也就是将链表的结构和链表的数据分开定义。 一般数据结构的书中介绍到的链表都是将链表的数据和链表的结构一起定义的。 注: 具体介绍可以我之前的博客参见: http://www.cnblogs.com/wang_yb/archive/2013/04/16/3023892.html 中的 1.2节 里面很重要的一点就是:链表结构和数据分开后,是如何通过链表节点结构来获取数据的? 带有safe的函数或者宏都是可以用于多线程的 1.2 修改部分

Linux 内核链表 list.h 的使用

人盡茶涼 提交于 2020-03-18 07:15:46
Linux 内核链表 list.h 的使用 C 语言本身并不自带集合(Collection)工具,当我们需要把结构体(struct)实例串联起来时,就需要在结构体内声明指向下一实例的指针,构成所谓的“链表”。而为了实现对链表的操作,我们需要另外实现一系列的函数,例如添加、删除、搜索、复制等等。而利用 Kernel 源代码中自带的 list.h,则可以方便地实现任意类型结构体的串联。 编程需求 假设我有一个表示学生资料的结构体: #define MAX_STRING_LENGTH 50 typedef struct student { char first_name[MAX_STRING_LENGTH]; char last_name[MAX_STRING_LENGTH]; unsigned int age; } student_t; 传统的做法,当我们需要将一系列学生的数据串联起来,那我们需要在该结构体内部添加一枚指针: typedef struct student { char first_name[MAX_STRING_LENGTH]; char last_name[MAX_STRING_LENGTH]; unsigned int age; struct student *next; /* Look at dis ;p */ } student_t; 几乎每位 C

斐波那契堆(二)之 C++的实现

99封情书 提交于 2020-03-18 05:32:33
概要 上一章 介绍了斐波那契堆的基本概念,并通过C语言实现了斐波那契堆。本章是斐波那契堆的C++实现。 目录 1. 斐波那契堆的介绍 2. 斐波那契堆的基本操作 3. 斐波那契堆的C++实现(完整源码) 4. 斐波那契堆的C++测试程序 转载请注明出处: http://www.cnblogs.com/skywang12345/p/3659069.html 更多内容: 数据结构与算法系列 目录 (01) 斐波那契堆(一)之 图文解析 和 C语言的实现 (02) 斐波那契堆(二)之 C++的实现 (03) 斐波那契堆(三)之 Java的实现 斐波那契堆的介绍 斐波那契堆(Fibonacci heap)是一种可合并堆 ,可用于实现合并优先队列 。它比二项堆具有更好的平摊分析性能,它的合并操作的时间复杂度是O(1)。 与二项堆一样,它也是由一组堆最小有序树组成,并且是一种可合并堆。 与二项堆不同的是,斐波那契堆中的树不一定是二项树;而且二项堆中的树是有序排列的,但是斐波那契堆中的树都是有根而无序的。 斐波那契堆的基本操作 1. 基本定义 template <class T> class FibNode { public: T key; // 关键字(键值) int degree; // 度数 FibNode<T> *left; // 左兄弟 FibNode<T> *right; //

数据结构与算法作业——合并两个有序链表

对着背影说爱祢 提交于 2020-03-17 22:41:32
题目:将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 解题算法: class Solution { public : ListNode * mergeTwoLists ( ListNode * l1 , ListNode * l2 ) { if ( ! l1 ) return l2 ; if ( ! l2 ) return l1 ; if ( l1 -> val < l2 -> val ) { l1 -> next = mergeTwoLists ( l1 -> next , l2 ) ; return l1 ; } else { l2 -> next = mergeTwoLists ( l1 , l2 -> next ) ; return l2 ; } } } ; 结果: 来源: CSDN 作者: SuperF? 链接: https://blog.csdn.net/weixin_46338672/article/details/104825766

HashMap底层源码剖析

十年热恋 提交于 2020-03-17 19:17:23
HashMap底层源码剖析 数组+单向链表+红黑树 数组:    数组每一项都是一个链表,其实就是数组和链表的结合体 单向链表:    当法神hash碰撞时,首先会找到数组对应位置,然后1.8采用尾插入法(1.7采用头插入法),形成一个单项链表结构 红黑树:   当数组中每项的链表长度大于8时,会转换为红黑树 什么是hash碰撞?解决方案 hash碰撞:    不同的key可能会产生相同的hash值; 方案:    链表发,再哈希法; hashMap中采用链表发,在ConcurrentHashMap中采用哈希法; 为什么采用红黑树,比如二叉查找树,并且为什么临界值为8    二叉查找树在特殊情况下也会变为线性结构,和原来链表有共同的问题,节点太深,查找性能慢 使用红黑树主要用于提升查询速度,红黑树是平衡二叉树的一种,插入新的数据都会通过左旋,右旋,变色等操作来保持平衡,解决节点的深度问题   当数据较少时,采用链表要比红黑树效率高,因为平衡二叉树保持平衡需要耗费资源,那么前期数据较少时采用链表,当数据到达一定的界限后,再采用 红黑树,可以加快数据查询速度,官方测试8为性能最优 put()底层源码剖析 public V put(K key, V value) { return putVal(hash(key), key, value, false, true);     } /**