链表

JavaScript实现树结构(一)

|▌冷眼眸甩不掉的悲伤 提交于 2020-03-09 08:52:08
JavaScript实现树结构(一) 一、树结构简介 1.1.简单了解树结构 什么是树? 真实的树: 树的特点: 树一般都有一个 根 ,连接着根的是 树干 ; 树干会发生分叉,形成许多 树枝 ,树枝会继续分化成更小的 树枝 ; 树枝的最后是 叶子 ; 现实生活中很多结构都是树的抽象,模拟的树结构相当于旋转 180° 的树。 树结构对比于数组/链表/哈希表有哪些优势呢: 数组: 优点:可以通过 下标值访问 ,效率高; 缺点:查找数据时需要先对数据进行 排序 ,生成 有序数组 ,才能提高查找效率;并且在插入和删除元素时,需要大量的 位移操作 ; 链表: 优点:数据的插入和删除操作效率都很高; 缺点: 查找 效率低,需要从头开始依次查找,直到找到目标数据为止;当需要在链表中间位置插入或删除数据时,插入或删除的效率都不高。 哈希表: 优点:哈希表的插入/查询/删除效率都非常高; 缺点: 空间利用率不高 ,底层使用的数组中很多单元没有被利用;并且哈希表中的元素是 无序 的,不能按照固定顺序遍历哈希表中的元素;而且不能快速找出哈希表中 最大值或最小值 这些特殊值。 树结构: 优点:树结构综合了上述三种结构的优点,同时也弥补了它们存在的缺点(虽然效率不一定都比它们高),比如树结构中数据都是有序的,查找效率高;空间利用率高;并且可以快速获取最大值和最小值等。 总的来说:

Day 9 环形链表

梦想的初衷 提交于 2020-03-09 07:11:42
环形链表 给定一个链表,判断链表中是否有环。 为了表示给定链表中的环,我们使用整数 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 解释:链表中没有环。 使用语言:C++ /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public : bool hasCycle ( ListNode * head ) { ListNode * fast = head ; ListNode * slow = head ; if ( head == NULL ) return false ; while ( fast &&

算法解析:通过快慢指针判断链表是否存在环并找到环的起点

梦想与她 提交于 2020-03-09 06:17:11
问题描述 给定一个单向链表,请判断该链表是否存在环;如果存在的话,请找到环的起点。 重要 注1:为了描述方便,后文中除非特殊指定,否则将“ 单向链表 ”简称为“ 链表 ” 注2:本文以包含头结点的链表为例,如果是一个不含头结点的链表,因为起始位置不同,所以一些变量的定义会受到影响,但不影响本文讨论的解题方法 问题分析 一般情况下,一个链表存在一个 尾结点 ,该结点的 next 指针为空。然而,当一个链表的 尾结点 指向了之前的某个前序结点时,链表就出现了“ 环 ”: 本题就是要判断一个给定的链表是否存在环,并找到环开始的位置。 注:严格来说,有环链表是没有尾结点的,因为不存在“ 最后一个结点 ”。但后文为了描述方便,仍然将指向环首结点的这个结点称为 尾结点 。 解题方案 可以通过 快慢指针 来判断一个链表是否有环。 什么是快慢指针 在一个链表的头结点处设置两个指针 slow 和 fast 并同时向前移动,规定 slow 每次移动一个结点, fast 每次移动两个结点,这就是快慢指针。 如何利用快慢指针判断链表存在环 如果链表不存在环,则肯定存在一个结点,其 next 指针为空,所以,只要 fast 在移动过程中遇到了空结点,则证明链表不存在环。 如果链表存在环,那么,因为 fast 移动速度比 slow 要快,所以,一定会在某些时刻, fast 会从后面追上 slow 。问题在于:

ConcurrentHashMap总结

不羁的心 提交于 2020-03-09 05:28:16
原文:https://my.oschina.net/hosee/blog/675884 并发编程实践中,ConcurrentHashMap是一个经常被使用的数据结构,相比于Hashtable以及Collections.synchronizedMap(),ConcurrentHashMap在线程安全的基础上提供了更好的写并发能力,但同时降低了对读一致性的要求(这点好像CAP理论啊 O(∩_∩)O)。ConcurrentHashMap的设计与实现非常精巧,大量的利用了volatile,final,CAS等lock-free技术来减少锁竞争对于性能的影响,无论对于Java并发编程的学习还是Java内存模型的理解,ConcurrentHashMap的设计以及源码都值得非常仔细的阅读与揣摩。 这篇日志记录了自己对ConcurrentHashMap的一些总结,由于JDK6,7,8中实现都不同,需要分开阐述在不同版本中的ConcurrentHashMap。 之前已经在 ConcurrentHashMap原理分析 中解释了ConcurrentHashMap的原理,主要是从代码的角度来阐述是源码是如何写的,本文仍然从源码出发,挑选个人觉得重要的点(会用红色标注)再次进行回顾,以及阐述ConcurrentHashMap的一些注意点。 1. JDK6与JDK7中的实现 1.1 设计思路

堆栈的详细讲解

不想你离开。 提交于 2020-03-09 04:57:02
在讲解堆栈之前,先让我们对堆栈有一个感性的认识 使用栈 :就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。 使用堆 :就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。 再了解一下堆栈的定义和函数调用的过程中堆栈的样子 记住堆栈定义中标黄的重点,对理清函数调用过程帮助非常大。 堆栈的定义 :堆栈是一种数据结构,具体是一个特定的存储区或寄存器。堆栈都是一种数据项按序排列的数据结构。 只能在一端(称为栈顶(top))对数据项进行插入和删除,也就是它的一端是固定的,另一端(栈顶)是浮动的 ,严格按照“先进后出”的原则存取,位于其中间的元素,必须在其栈上部(后进栈者)诸元素逐个移出后才能取出。 因而栈顶地址总是小于等于栈的基地址。 #include <stdio.h> void __stdcall func(int param1,int param2,int param3) { int var1=param1; int var2=param2; int var3=param3; printf("0x%08x\n",param1); //打印出各个变量的内存地址 printf("0x%08x\n",param2); printf("0x%08x\n\n"

如何实现链表的逆序

不想你离开。 提交于 2020-03-09 00:32:28
package com.example.lib; public class LianBiao1 { public static void main(String[] args) { LNode head=new LNode(); LNode next=null; for(int i=1;i<=7;i++){ LNode cur=new LNode(); cur.data=i; if(head.next==null){ head.next=cur; next=cur; }else { next.next=cur; next=cur; } } next.next=null; Reverse(head); printNode(head); } public static void printNode(LNode head){ StringBuffer buffer=new StringBuffer(); LNode cur=head.next; while (cur!=null){ buffer.append(" "+cur.data); cur=cur.next; } System.out.println(buffer.toString()+"\n"); } public static void Reverse(LNode head){ //head-> 1 ->2 ->3 -> 4

《算法4》散列表实现笔记

半城伤御伤魂 提交于 2020-03-09 00:19:39
一、散列函数 散列函数会将键转为数组的索引。我们的散列函数应该计算速度快且能够均匀分布所有的键,如对于大小为M的散列表,我们的散列函数应当能够让任意的key都能够转化为 0-到M-1 的整数,对于不同的键应该有不同的散列函数。Java中许多常用的类都重写了hashCode方法,以针对不同的数据类型使用不同的散列函数。 二、基于拉链法的散列表 散列算法理想的状态是将不同的key都转为不同的索引值,但这显然是不可能的,一定会产生冲突,因此我们就需要对冲突进行处理。 一种直接的方法 是将大小为M的数组中的每个索引指向一条链表,链表中的每个节点都存储了散列值为该链表所在索引值的键值对 ,这种方法就是 拉链法。 如下是基本数据结构: public class SeparateChainingHashST < Key , Value > { /** * 键值对总数 */ private int N ; /** * 散列表大小 */ private int M ; private SequentialSearchST < Key , Value > [ ] st ; public SeparateChainingHashST ( ) { this ( 997 ) ; } public SeparateChainingHashST ( int M ) { this . M = M ; st =

DS01-线性表

南楼画角 提交于 2020-03-08 23:23:47
1.本周内容总结 1.1总结线性表内容 顺序表结构体定义 typedef struct LNode *List struct LNode { ElementType Data[MAXSIZE]; int last; }; struct LNode L; List PtrL; 顺序表插入 void Insert(ElementType X, int i; List PtrL) { int j; if (PtrL->Last == MAXSIZE - 1) { cout << "表满"<<endl; return; } if (i < 1 || i> PtrL->Last + 2) { cout << "位置不合法" << endl; return; } for (j = PtrL->Last; j >= i - 1; j--) { PtrL->Data[j + 1] = PtrL->Data[j]; } PtrL->Data[i - 1] = X; PtrL->Last++; return; } 顺序表删除 void Delete(int i, List PtrL) { int j; if (i<1 || i>PtrL->Last + 1) { cout << "不存在第" << i << "个元素" << endl; return; } for (j = i; j <= PtrL-

DS博客作业02-线性表

一曲冷凌霜 提交于 2020-03-08 23:22:33
0.PTA得分截图 1.本周学习总结 1.1 总结线性表内容 什么是线性表? 定义: 线性表是具有相同特性的数据元素的一个有限序列。 线性表一般表示: (a1,a2,a3...ai..an) 这里a1为表头元素,an为表尾元素。 线性表特征: 1.元素个数n——表长度; n=0——空表 2.1<i<n时 a[i]的直接前驱是a[i-1],a[1]无直接前驱 a[i]的直接后继是a[i+1], a[n]无直接后继 3.元素同构,且不能出现缺项 线性表的抽象数据类型描述 ADT List { 数据对象D={ai|ai∈Elemset, i=1,2, . n, n≥0} 数据关系: R={<ai-1, ai>|ai-1,ai∈D, i=2, .., n} 基本操作: InitList (&L) :构造一个空的线性表L DestroyList (&L) :销毁线性表L占用内存空间 ListEmpty(L):若线性表L为空表,则返回TRUE,否则返回FALSE ListLenght(L):返回线性表L数据元素个数 GetElem(L, i, &e):用e返回线性表L中第i个数据元素的值 LocatElem(L,e):返回L中第一个值域与e相等的逻辑位序。若这样的元素不存在,则返回值为0。 ListInsert(&L, i,e) : ListDelete(&L, i, &e) : } /

伙伴系统和slab机制

*爱你&永不变心* 提交于 2020-03-08 22:17:34
伙伴系统 Linux内核中采用了一种同时适用于32位和64位系统的内存分页模型,对于32位系统来说,两级页表足够用了,而在x86_64系统中,用到了四级页表。四级页表分别为: 页全局目录(Page Global Directory) 页上级目录(Page Upper Directory) 页中间目录(Page Middle Directory) 页表(Page Table) 页全局目录包含若干页上级目录的地址,页上级目录又依次包含若干页中间目录的地址,而页中间目录又包含若干页表的地址,每一个页表项指向一个页框。Linux中采用4KB大小的页框作为标准的内存分配单元。 在实际应用中,经常需要分配一组连续的页框,而频繁地申请和释放不同大小的连续页框,必然导致在已分配页框的内存块中分散了许多小块的空闲页框。这样,即使这些页框是空闲的,其他需要分配连续页框的应用也很难得到满足。 为了避免出现这种情况,Linux内核中引入了伙伴系统算法(buddy system)。把所有的空闲页框分组为11个块链表,每个块链表分别包含大小为1,2,4,8,16,32,64,128,256,512和1024个连续页框的页框块。最大可以申请1024个连续页框,对应4MB大小的连续内存。每个页框块的第一个页框的物理地址是该块大小的整数倍。 假设要申请一个256个页框的块,先从256个页框的链表中查找空闲块