数据结构源码分析目录

libevent源码分析之目录结构说明 一、概述 1、目录分类: 头文件:分为提供给外部使用的头文件和内部使用的头文件。 reactor框架:包括事件的定义、事件的监听和触发、定时器功能。 io多路复用封装:包括select、poll、epoll、iocp、kqueue等。 socket、收发缓冲区封装:网络缓冲区evbuffer实现,bufferevent管理了socket和网络缓冲区。 基础数据结构:链表、最小堆、红黑树、哈希表等。 dns、http库:基于libevent实现。 其他:辅助功能函数、日志。 2、具体文件说明 1) 阅读详情

说明

  • Github上更新的较这里勤

  • 会包括常见的数据结构,这里应该只会说明一个大概,具体的源码一步一步会单独的抽出一篇文章来写的,不过最近没啥时间,可能会慢点,不过之前的时候整理过一部分

  • 现在还是浅层的,要深层的话必须详细的看源码一步一步来,但是现在时间不是很充裕,暂且如此

TODO

  • 红黑树

HashMap源码剖析

  • HashMap源码

    • hashMap实现了Map,Cloneable,Serializable接口,继承了抽象Map类
    • hashMap线程不安全,允许key,value都为null,遍历的时候是无序的
      • 线程不安全体现于:
        • 数据丢失: 存在2个hashCode相等的对象(对象不同),同时定位到并且得知bucket的下标为空,并且都赋值,也就使得后者的数据会覆盖前者的数据,或者是next连接赋值的时候
        • 死循环:这个问题在8中已经被解决了,在7中因为会发生链表反转,因而会导致死循环,而再8中通过2个链表,lo和hi将原先的链表分为2个部分,通过与原先的长度做&运算判断是否需要移动
        • 如何得知线程不安全:通过modCount,hashMap有一个fail-fast策略,在迭代的时候modCount会赋值给迭代器的exceptModCount中,迭代过程中modCount会变化,因而会导致不相同,因此就会抛出异常
    • 底层解决hash冲突的方法是链地址法,既数组加链表的形式来解决hash冲突,当链表长度大于8的时候会把链表转成红黑树,链表长度低于6,会把红黑树转回链表
      • hashMap负载因子的作用:
        • 负载因子的计算为: 扩容的阈值/容量
      • 减少hash冲突:hash冲突与两方面有关:hash算法和负载因子,原因在于,在好的hash算法,当负载因子过小的时候也会导致大量的hash碰撞,此外,再大的负载因子当hash算法很差的时候也会导致大量冲突
        • 采用不可变性作为key,如String,Integer;为什么? 因为这些键当key的值所确定的时候hashCode就不会发生变更了,而如果我们想用自定义的作为key的时候,复写hashCode方法必须选取变化少,并且独一无二的值
      • 8中的hash算法:hashCode低16位与高16位做异或运算,然后与容量做与运算即可获取下标
        • 为什么低16位与高16位做异或:这个问题衍生出如下子问题:
          • 为什么要移位:
            • 弄清需要先明白:
              • “>>” 和">>>"的区别:前者是有符号的右移动,后者是无符号的右移动,既前者-3,2还是会为负数,正数,而后者则统一为正数
              • 然后反证法,若没有移16位做与运算,则若有111…000000,和100111…0000 当直接与15做与运算的时候会发现index永远为0,所以我们肯定是需要移位的
          • 为什么是16位:
            • 同样反证法,如果移动[1-16)位,我们可以发现高位上的特征会发现没有利用,试想一下就可以明白,移到8位高位上[23,31]下标的值还是处于高位,并没有利用
            • 再反正法,如果移动[17,31)位,这个更加浅显,我们hashCode大部分值都丢失了(wtf),因而绝对不可取
            • 所以,总结:移动16位的原因在于:充分利用高16位的特征与低16位的特征,从而得到一个重复率小的值
          • 为什么是异或
            • 什么是异或: 异或是指相同的为0,不同的则为1
            • 为什么不用& 或者是| :
              • & 只有都为1的时候才会为1,因而更加靠近于0
              • | 有一个1就是为1,更加靠近于1
              • 两者都过于有倾向性,而异或^使得高16位与低16位的特性充分发挥
        • 为什么用&替代%:原因无它,%是除法运算,而除法运算是现代计算机很慢的
        • 为什么HashMap的容量肯定是2的n次幂,为什么要-1:
          • 这个问题可以这么理解:
            • 2的n次幂有什么特定:
              • 在计算机中,数据都是0,1;而当这个值都为1的时候,只要本身输入的hashCode合理,则很少冲突
            • 2的n次幂能带来什么好处
              • 二进制都为1并且通过与运算使得hashCode充分分散
                • 具体的例子,容量为10:
                  • 1010 & 101010100101001001000 结果:1000 = 8
                  • 1010 & 101000101101001001001 结果:1000 = 8
              • 扩容resize的时候也是以2的n次幂为基础的,也就使得,原先的元素要么在原位置,要么在移动2的n次幂处
                • 原理如图: a为扩容前,b为扩容后,扩容是扩大当前容量的2倍(既左移1位),则我们可以根据图发现,hash2扩容后只需要移动原先容量位置即可
                • 具体示例图: ,通过与原先的容量进行&运算判断是否==0,为0则不需要移动
        • 总结: 2的n次幂,使得当做与运算的时候,2^n-1 在计算机中都是0,1;只要本身hashCode合理,就会分散均匀,并且,使得元素扩容的时候要么不移动,要么移动原先容量的长度即可
        • 红黑树:
          • 特性:
            • 每个节点要么黑要么红
            • 根节点都是黑色的
            • 如果节点是红色的,则子节点必须是黑色的
            • 从根节点到叶子节点或者空节点,期间遇到的黑色节点数是相同的
    • hashmap达到threshold的时候,会发生扩容,且扩容前后hash桶的长度肯定为2的次方,移动元素因为2^n的特性,要么不移动,要么移动一次(距离为之前容量)即可
    • hashmap的hash函数是通过hashCode与hashCode的高16位做异或运算得到的
    • hashmap内部充斥着位运算来提升效率
    • 对比7的优化:
      - 插入: 在7中插入是头插法,而在8中链表是尾插法
      - 扩容: 在7中是遍历旧的数组,然后遍历重新计算hash然后填入到新的拉链中,而在8中,则是通过lo和hi2个链表,lo代表不用移动的的,hi中的索引为原先的index+原先的容量值,因为充斥着位运算,所以8中移动元素要么在原位置,要么仅需要移动2次幂(也就是原索引+原先容量的位置即可)即可,而如何判断是lo串还是hi串,则仅需要通过索引和原先容量做位运算判断即可,同时也因为如此避免了线程不安全的死循环问题
  • ConcurrentHashMap源码:

    • chm是线程安全的类,不允许key,value为null
    • 核心数据如链表都是被volatile所修饰的
    • sizeCtl是一个同步的共享变量,用于同步线程(内部是通过cas实现设置的)
      • 用处:
        • 初始化的时候
          • WIP,这里结合代码代码更好如果这个值<0 .代表正在初始化|扩容|红黑树,则当前线程会Thread.yield让出cpu时间,否则当前线程会尝试自旋修改sizectl(这个线程初始化),成功的时候会double check(非锁) 防止重新初始化
        • 扩容的时候:
          • WIP同上: 当发现扩容的时候当前线程会参与到扩容,然后sizeCtl会+1,代表当前有sizeCtl个线程正在帮助扩容
    • 查询操作与HashMap类似,都是先获取hash,然后与运算获取index,然后通过判断hashCode是否<0判断是否是红黑树,是则红黑树取值,否则链表遍历取值
    • get:
      • 16位异或->& HASH_BITS(消除负位)->&(size-1)获取下标判断是否为空
      • 获取链首的Node,判断hash,equals是否满足
      • 不满足,则判断元素的hash是否小于0,小于0代表是树节点或者是正在扩容,则会依据其类型重写的find方法去查找
      • 如果不是说明在链表中,则遍历取值
    • put:chm初始化是在put的时候才会初始化的
      • spread获取hash(注意这一步较常规的hashMap多了一步去除负位)
      • 判断数组是否已经初始化了,如果没有则初始化
      • 与运算cas尝试设置值
      • 获取hash判断是否正在扩容(并且正在扩容的话,这个类型会是ForwardingNode(`用于连接2个表,既扩容是的lo和hi表``))
      • 否则锁住这个头部,然后双重检测防止其他线程插入覆盖,内部会通过这个hash值判断是树呢还是链表
      • 插入完毕之后会addCount,内部判断是否需要扩容,如果正在扩容则帮助其扩容
    • remove:
      • 删除操作与put操作类似
      • spread获取hash
      • 判断下标所处的是否处于正在扩容,如果正在扩容则帮助扩容
      • 否则的话锁住这个链头,然后再双重检测,再判断hash是否>0,大于0代表无任何其余操作
      • 小于0则判断是否是红黑树,无论是红黑树还是链表,删除之后都会重新设定链表头部
    • 在1.7中是通过分段锁的形式,既内部是segment数组,每个segment都是一个单独的锁,在1.8则是采用cas+红黑树的形式,当然锁也是存在的,但是颗粒度还是比7小的
    • 注意点
      • hash算法与HashMap不同,多了一步: 多了一步 &HASH_BIT
        • 原因在于:&HASH_BITS,HASH_BITS是0x7fffffff,该步是为了消除最高位上的负符号 hash的负值在ConcurrentHashMap中有特殊意义表示在扩容或者是树节点
    • 总结:(部分)
      • CHM很关键的一个点在于:sizeCtl和spread这个hash函数
        • sizeCtl<0 代表的是正在扩容,初始化或者代表是红黑树
        • spread与hash函数不同,spread多了一步& HASH_BITS,因为对CHM而言,hash小于0是有特殊意义的
      • 每次插入删除修改都会判断这个table节点的下标的hash是否处于某种特定的状态,如:是否正在扩容,还是啥也没有,还是说是红黑树节点
      • CHM使用锁的地方都是在table的首节点上加锁的
      • 学到的思路: 用一个共有变量代表线程,或者元素的状态

ThreadPool源码剖析

  • 仅将现阶段的笔记先敲上,具体的源码后序再补
  • ThreadPool源码
    • 线程池的作用:
      • 降低性能消耗,提高响应速度:当应用需要频繁创建线程,而线程的创建是需要消耗额外的资源的
      • 线程集中管理,可以对线程池中的状态和数量进行集中管理
    • 参数
      • corePoolSize: 核心线程池的数目,既一直存活着的线程数
      • maximunPoolSize: 最大线程数目,当核心线程池满了,然后无法将任务添加到缓存队列的时候会将任务用额外的线程创建并执行
      • keepAliveTime: 线程存活时间,这个参数只有当corePoolSize满的时候才会起作用
      • timeUnit: 时间类别,与keepAliveTime一起构成线程存活时间的约束
      • workQueue: 阻塞队列,有如下几种:
        • ArrayBlockingQueue : 有界阻塞队列:
        • SynchronousuQueue: 没有容量的阻塞队列,一次添加必须等待一次获取
        • LinkedBlockingQueue: 无界阻塞队列
        • 关于LinkedBlockingQueue和ArrayBlockingQueue的区别:
          • 底层结构不同:LinkedBlockingQueue内部是链表,而ArrayBlockingQueue的内部是数组
          • 锁不同: linkedBlockingQueue读写是分开的2把锁putLock和takeLock,而arrayBlockingQueue是公用一把锁
          • 初始化不同:LinkedBlockingQueue初始化时不需要指定长度,默认是Integer.MAX_VALUE而ArrayBlockingQueue初始化的时候需要指定长度
      • threadFactory: 线程工厂,用于统一创建具有某种特征的线程
      • rejectHandler: 拒绝策略,有如下几种策略
        • AbortPolicy: 直接抛出异常策略
        • CallerRunsPolicy: 既这个线程直接运行这个任务(当然线程未处于shut down状态)
        • DiscardOldestPolicy: 抛弃策略,抛弃任务等待队列中等待最久的那个任务(既末尾任务),然后将这个任务插入到队尾中
        • DiscardPolicy: 抛弃策略,既什么都不管,直接丢弃
      • 一些重要的参数:
        • ctl:控制着整个线程池的运行,利用高3位代表线程池的状态,低29位代表线程池的数目
          • 各个状态的含义:
            • running: 代表运行状态,是初始化的时候的状态
            • shutdown: running->调用shutdown->进入shutdown状态,此时线程池不接受新的任务,但是能处理已经添加的任务
            • stop: (running|shutdown)->调用shutdownNow()->进入stop状态,不接受新的任务,并且也不再执行已经添加的任务,同时会中断正在执行的任务
            • tidying:当线程池内线程数为0且队列中任务数为0时shutdown->tidying ; 当线程池内线程数为0时:stop->tidying
            • terminated: 当处于tidying 执行完termiated之后就会处于terminated状态
      • 线程池的执行流程:

        尝试创建核心线程->核心线程已满->添加任务到缓存队列中->如果缓存队列也满了->创建非核心线层->如果无法创建非核心线程->执行拒绝策略
  • 疑惑点
    1. 为什么使用cas+synchronized代替segment+lock
      • 这里问题需要先拆分:
        • segment是什么,为什么不用segment:
          • 答: segment可以认为是一个8的hashMap,内部是一个数组,每个数组又是一个链表,并且Segment继承了Lock,本身就是一个锁(可见锁的颗粒度是很大的)
            因而为什么不用segment的原因也很明显了,降低锁的颗粒度
        • 为什么使用CAS:
          • 答: 传统的竞争如果获取不到锁,会进入wait状态,也就是说会从用户态进入内核态,至于什么是内核态,什么是用户态,字面翻译即可,而用户态到内核态开销大,那么cas是什么呢,cas可以认为是一个死循环,也就是说他不会进入阻塞状态,所以CAS适用于业务时间小于上下文切换的时间
            所以这里就延伸出了答案,如下:
        • 为什么使用Synchronized
          • 答:
            • 内存方面,每个lock内部的sync继承了aqs,也就引入了额外的内存空间,而synchronized因为jvm 内部对象的特性,并不需要额外引入
            • 性能方面: 如第一个小问,锁已经被细化了,那么竞争还会那么激烈吗,往往循环30-50(瞎想的)次就会获取到锁(synchronized的偏向锁),那么也就避免了线程上下文切换的开销
              而如果用lock,lock当第一次无法获取则会再创建一个node,再尝试获取,再获取不到则挂起(首先这里的性能就相比差了),并且在这期间是不会发起自旋的,自旋只会在判断state的时候
              因此使用synchronized代替lock
      • 总结:
        • 内存占用减少
        • 锁的颗粒度更加小,导致并发量不大,在并发量不大的情况下那么Synchronized因为自旋锁,偏向锁,轻量级锁的原因,不用将等待线程挂起,偏向锁甚至不用自旋,所以在这种情况下要比ReentrantLock高效
    • WIP写给自己:
      • lock和synchronized的性能主要区别在于唤醒线程的数量: synchronzied是所有线程,而lock则是链表的下一个节点以及刚插入的节点(nonfair)
      • reentrantlock该重新补了,

HashSet源码

  • HashSet源码:
    • HashSet实现了set,cloneable,serializable接口,继承了AbstractSet抽象类
    • hashSet的本质其实还是HashMap,内部的是通过HashMap+ static final类型的object来实现的,这个object对象是充当为value,其他充当为key,这样通过hashMap就能判断之前是否存在值了

TreeMap源码

  • TreeMap源码
    • 有一个Comparator成员变量,每当插入一个值的时候都会通过这个去进行匹配
    • TreeMap的底层是完全二叉树,当插入值的时候除了常规的校验,就是正常的二叉树的遍历匹配,然后插入

TreeSet源码

  • TreeSet源码
    • TreeSet的底层与HashSet类似,但是不同在于TreeSet的map选型是TreeMap,TreeMap的底层是完全二叉树

ArrayList和LinkdList的区别及其源码

  • ArrayList和LinkedList的区别及其源码
    • ArrayList的底层是数组,而LinkedList的底层是链表
    • ArrayList默认的数组长度为10,每次插入之前都会先判断是否需要扩容,当扩容时候调用的函数是System.arrayCopyOf
    • ArrayList适合于读多,插入删除少的场景,因为插入删除很可能会导致数组的copy,而linkedList非常适合于插入或者删除

线程安全的集合:

  • CopyOnWriteArrayList: 适用于读多写少的场景,底层是数组,读的时候不会加锁,写的时候会加全局锁
  • CopyOnWriteArraySet: 底层是CopyOnWriteArrayList,如何去重呢?插入之前会先通过indexOf判断值是否存在,当真正插入加锁的时候,又会判断是否存在值(既双重检测)

volatile的作用及其原理

  • 作用:
    • 内存可见性: 线程共享进程的内存,每个线程都会拷贝一份内存,但是当被volatile修饰的时候并不会拷贝,因而每次都是从主内存中读取或者写入
    • 防止重排序:Java的haapens-before原则,既既如锁的unlock必定在lock之后,所以volaitile的写必定是在读之前(每次被线程访问的时候都是从主内存中读取值,当值变化时又会强制刷新到主内存中,这样每个线程获取到的都是最新的值)
      • 内存屏障:
        - 被volatile所修饰的变量,赋值的时候会设定一个内存屏障,后面的指令不能排到内存屏障之前
    • 原子性: 每个操作都是原子性的(单个操作,并不是指i++这个复合操作也是原子性的)
  • 内存间的交互原理: 既一个变量如何从主内存拷贝到工作内存,如何从工作内存同步回主内存
    • lock
    • unlock
    • read(读取): 从主内存中读取值,准备载入
    • load(载入): 这一步在read之后,将read读取到的值放入到工作内存的副本中,但是并没有使用
    • use(使用): 既工作内存使用这个值
    • assign(赋值): 上一步的使用并不代表赋值,这一步才是真正的赋值操作,代表可以运行了
    • store(存储): 工作内存的值准备刷新到主内存
    • write(写入): 工作内存中更新值
  • volatile对上述交互做的约束:
    • 如果要执行load,则下一步必须是read,如果下一步是read,上一步必须是load,既load-read必须连续出现,使得每次使用的时候都是从主内存中获取最新的值
    • 内存可见性/原子性原理: assign-store-write 必须连续出现,使得每次操作都会强制刷新到主内存
    • 重排序原理: 既如果A操作的 F行为 比B 操作的F行为优先,则 A操作之后的G行为必定优先于B操作的G行为

Synchronized和lock的区别:

  • Synchronized的是虚拟机层面的而lock是代码层面的
  • 锁的释放: synchronized会自动释放,而lock需要我们手动释放
  • 锁的获取: synchronized只能硬性获取,而lock可以尝试获取或者等待获取一段时间
  • 锁的状态: synchronized无法判断锁的状态,而lock是可以判断的
  • 锁的类别: synchronized的锁可重入,不可中断,非公平,而lock可冲入,可判断,可中断,并且可公平和非公平(lock默认是非公平锁)

Synchronized原理:

  • mark world是虚拟机中对象对象头的信息
  • 对于同步代码块而言:synchronized是基于jvm的,为什么说基于jvm的呢,因为当加载到内存中的时候,每个对象都会有一个monitor对象,而每次试图获取锁都会先判断内部的objdef的monitor是否为0,为0的话可以获取monitor,然后退出的时候-1,moniterexit并且如果当异常发生的时候也会调用moniterexit,并且可重入,重入的时候会+1
  • 对于synchronized方法而言:不是通过字节码实现同步的,而是通过方法常量池中的方法表结构中的一个标志ACC_SYNCHRONIZED来判断是否是同步方法,如果设置了则执行线程先获取,然后释放monitor
  • 在讲锁之前需要了解下,对象实例及类在JVM中的分布情况:
    • 对于对象实例或者是方法区中的类信息,JVM都为其配备了Monitor对象:
      • 对象实例在JVM的堆中,有一个对象头的概念:Object Header,这个对象头存放了两部分信息:
        • 官方称为:Mark Word 第一部分:对象的hashCode,对象的GC分代年龄,锁状态标识,线程持有的锁,偏向线程ID,偏向时间戳
        • 另一部分: 类型指针: JVM通过这个判断这个对象属于哪个类的实例
  • synchronized中相关的锁的结构:
  • 锁一般分为
    • 乐观锁: 顾名思义,撤销都是结束的时候判断,并且一般都是通过cas来实现的(偏向锁,自旋锁以及轻量锁都是乐观锁)
    • 悲观锁: 既先执行加锁(重量级锁是悲观锁)
    • 偏向锁:是针对加锁操作的优化,因为大多数情况下都是同一个线程获取到了锁,所以引入偏向锁的概念,在这种锁的情况下,Mark Word的结构也会变成偏向锁结构,当这个线程再次获取的时候就不会做任何同步的优化效果 (先通过判断对象的偏向状态,如果有则表明存在竞争,如果原先的已经挂了,则变为无锁状态,然后重新偏向,若原先的没挂,则先检测原先的是否还需要用,要用则升级会轻量级锁,否则将对象回复称无锁,然后重新偏向)
    • 轻量级锁: 偏向锁代表只有一个线程竞争,而再来一个任务之后偏向锁就会升级为轻量锁,当偏向锁升级到轻量级锁的时候,Mark World的结构也会变成轻量锁的结构,
      适合于线程交替执行的场景 (判断这个对象是否被持有(因为会传递线程的地址),如果被持有则会自旋,当超过一定次数,或者又有新的来参与竞争则会升级为重量级锁)
    • 自旋锁: 既while死循环一段时间,适用于那些锁时间非常短的代码,避免内核态到用户态的消耗
    • 锁使用情景的总结:
      • 偏向锁: 只有一个线程进入临界区
      • 轻量级锁: 多个线程交替进入临界区
      • 重量级锁: 多个线程同时进入临界区
  • synchronized中获取锁的具体流程总结:
    1. 检测MarkWord里面是不是当前线程的ID,如果是,表示当前线程处于偏向锁
    2. 如果不是,则使用CAS将当前线程的ID替换Mard Word,如果成功则表示当前线程获得偏向锁,置偏向标志位1
    3. 如果失败,则说明发生竞争,撤销偏向锁,进而升级为轻量级锁。
    4. 当前线程使用CAS将对象头的Mark Word替换为锁记录指针,如果成功,当前线程获得锁
    5. 如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
    6. 如果自旋成功则依然处于轻量级状态。
    7. 如果自旋失败,则升级为重量级锁
  • 代码中的锁优化:
    • 减少锁的时间: 既synchronized包裹的代码块越少越好
    • 减小锁的粒度:思想是将物理git上的锁拆分成多个锁,如1.7中的chm,每个segment都是一个锁
    • 使用cas+volatile: 如果同步的操作非常快,时间短暂(既上下文切换的时间比逻辑时间要长),并且线程竞争并不激烈

ReentrantLock的原理:(待补)

  • ReentrantLock的实现是通过将任务委托给Sync,而Sync继承了aqs,aqs内部通过state变量来控制同步状态,当state=0时代表没有任何线程占有锁,而当为1的时候线程会进入同步队列中,通过Node实现线程的FIFO,又会通过ConditionObject构建等待队列,当Condition调用wait的时候会进入等待队列而signal则会进入同步队列竞争锁
数据结构源代码(c语言版本) 本资源包括了数据结构中的所有源代码,包括线性表,栈和队列,串,树,图,查找,排序,并且源代码是用c语言描写 立即下载

相关推荐

数据结构与算法视频课程(59集)

资源名称:数据结构与算法视频课程(59集)资源目录:【】mysql视频教程第41讲存储过程【】数据结构与算法_1.10算法的评价【】数据结构与算法_1.1编程的灵魂:数据结构 算法【】数据结构与算法_1.2算法的作用:猜价格游戏【】数据结构与算法_1.3递推算法【】数据结构与算法_1.4枚举(穷举)算法【】数据结构与算法_1.5 资源太大,传百度网盘了,链接在附件中,有需要的同学自取。

数据结构与算法(C++版)

下载地址:http://pan.baidu.com/s/1o6oRynK 提取密码:vwwk

1600

【24届计算机校招】面经汇总

这是笔者为了能够记录一下接下来一段时间会看的一些博客视频等汇总。一是为了汇总后常回来看看,而是为了后面的人在这个阶段准备的时候有个参考。现在已经6月底了,大部分高校的夏令营都出来了,而我至今还是夏0营,前几天还为川大会收双非而感到高兴,但遗憾的是川大并没要我。而我另一位双非的朋友已经拿到offer,在决定去南开还是华师了。没有对比就没伤害,我开始怀疑自己的决策是否正确——这段时间的夏令营我都有关注,但我仅报了少部分的几个酒吧舞,而没有选择海投,我觉得只要我认准了一个东西,我拼尽全力就一定能够获取到。

JehanRio's Private Blog 801

【数据结构】第一站:C语言--顺序表(附完整源码和注释)

顺序表是数据结构学习所接触的第一个数据存储结构,对顺序表的结构有清楚的了解,将对后面的学习大有帮助。(本文章默认读者c语言有一定了解)还需要注意的是:数据结构的学习,我们亲自画图(理解逻辑的过程)十分重要,如果顺序表不好好画图,相信链表的实现时会让你头疼一阵。

poplar的博客 5285

SAP CO模块实战:成本中心会计分割结构配置全流程(OKES事务码详解)

本文详细解析了SAP CO模块中成本中心会计分割结构的配置全流程,重点讲解了OKES事务码的实战操作。内容涵盖分割结构的概念理解、配置前的次级成本要素与作业类型主数据准备,并通过步骤拆解演示了如何定义分割结构、规则与版本,以及如何将配置关联到成本中心并执行分割。最后提供了常见问题排查与优化建议,旨在帮助顾问及财务人员掌握成本精确分摊的关键配置,确保期末成本核算的准确性。

embedding5hiker的博客 804

一个三极管和稳压管构成的简易稳压电源

一、对电压精度要求不高的场所可以使用本文中所述的简易稳压电源(电流变化引起 的基极-发射极的压降 变化 对输出电压来说可以容忍)二、根据负载实际需求选择三极管,不同的三极管集电极电流不同,电流放大倍数不同(1、尽量选择负载电流(iC 或 iE)上限时,hFE仍然比较理想的三极管,2、一般三极管对基极电流没有限制,可以适当调整基极电流以获得所需输出电流)

五花带点肉 1万+

数据结构课程设计(源代码)

【代码】数据结构课程设计(源代码)

m0_70588750的博客 795

HFSS仿真平行线定向耦合器学习笔记

材料:FR4(玻璃纤维环氧树脂),介电常数:4.4,损耗角正切:0.02,厚度0.8mm。扫频方式:快速扫频,扫频范围:1.0GHz~3.0GHz,步进:0.01GHz。端口2是端口1关于Y轴对称,端口3,端口4是端口1和端口2关于X轴对称得到。求解中心频率:2.0GHz,迭代次数:20,收敛误差为0.02。右键设置边界条件----辐射边界。激励方式:集总端口激励。

qq_36521926的博客 4486

【数据结构之顺序表】附源码【收藏】

文章目录????引言1️⃣静态顺序表静态 VS 动态2️⃣动态顺序表????实现接口目录????初始化????打印数据????空间销毁????尾部插入????尾部删除????头部插入????头部删除????任意位置插入????任意位置删除????查找数据????查找某数据并插入数据????查找某数据并将其删除????头部插入(调用任意位置插入接口实现)????尾部插入 (调用任意位置插入接口实现)????头部删除(调用任意位置删除接口实现)????尾部删除(调用任意位置删除接口实现)????自动扩容????

哆啦A梦_PJYA的博客 1720

避坑指南:在Linux服务器上用Conda安装antiSMASH 5.2.0(解决Jinja2报错和Matplotlib权限问题)

本文详细介绍了在Linux服务器上使用Conda安装antiSMASH 5.2.0的避坑指南,重点解决了Jinja2报错和Matplotlib权限问题。通过创建专用conda环境、安装指定版本依赖包和配置缓存目录,帮助用户顺利完成antiSMASH的本地部署,适用于批量处理基因组分析任务。

weixin_26911099的博客 314

centos7下100T存储扩容(LVM)至150T

查看新增磁盘情况lsblk,fdisk -l [root@localhost ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sr0 11:0 1 4.2G 0 rom vda 252:0 0 80G 0 disk ├─vda1 252:1 0 1G 0 part /boot └─vda2 252:2

tiyager的博客 1024

mosquitto源码分析

前词 由于前些天做的mqtt连接云平台项目测试过程中,发现了自身的代码在不良环境下,例如:网络断开、服务器断开的情况下,mqtt客户端无法感知连接已失效,仍然会继续向对端publish success。且在重新连接网络成功后,一下子重新往对端发送在连接失效的时间段内的发送数据,从而造成接收重复。 所以,自己去下载了mosquitto的源码,进行了系列分析。但是,由于本身能力有限,也不算很理解,如果有大哥是有了解的,还望私聊一起探索。 附上源码地址:https://github.com/eclipse/mos

weixin_46020788的博客 1859

RK3568平台YOLOv11模型部署全流程实战:环境搭建、模型转换与性能优化解析

在AI边缘计算领域,瑞芯微RK3568芯片凭借其强大的NPU算力和丰富的接口资源,成为了众多开发者的首选平台。然而,瑞芯微官方文档虽然提供了YOLO11预训练模型的部署方案,但对于需要自定义数据集训练的开发者来说,从模型训练到板端部署的完整流程却缺乏详细指导。本文将带你走完从环境搭建、数据准备、模型训练到最终板端部署的完整技术路线,并分享实际开发中遇到的各种坑点和解决方案。让我们一起探索如何在RK3568平台上实现30FPS稳定推理的YOLO11目标检测应用!

LXY_LOVE36的博客 120

2019最新《Java BAT大型公司面试专属必备技能实战教程》

课程目录:1.面试必考之HashMap源码分析与实现2.探索JVM底层奥秘ClassLoader源码分析与案例讲解3.面试必备技能之Dubbo企业实战4.分布式框架Zookeeper之服务注册与订阅5.互联网系统垂直架构之Session解决方案6.分库分表之后分布式下如何保证ID全局唯一性7.互联网企业必备高质量API网关接口设计8.大型公司面试必答之数据结构与算法精讲9.高性能网络编程必备技能之...

tianfazhishen的博客 186

在Android中实现SIM卡的读写操作

在上述代码中,我们创建了一个PhoneStateListener的实例,并重写了onSimStateChanged方法来处理SIM卡状态改变的事件。然后,我们通过调用telephonyManager的listen方法注册了这个监听器,并指定了要监听的事件类型为SIM卡状态的改变。在上述代码中,我们调用telephonyManager的sendUssdRequest方法来发送USSD命令,并通过TelephonyManager.UssdResponseCallback来处理USSD响应和发送失败的情况。

2301_79326510的博客 923

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

北邮数据结构实践项目指南

北邮数据结构实践项目指南 本教程旨在帮助您理解和操作名为“Data-Structure-in-BUPT”的开源项目,它包含了北京邮电大学(BUPT)数据结构课程的相关实验和解决方案。以下是关于项目结构、启动文件以及配置文件的详细介绍。 1. 项目目录结构及介绍 项目遵循清晰的结构以便于理解和维护: 根目录: src: 主要源代码存放地,根据实验或功能划分不同的子目录。 docs: 可能包含项目...

gitblog_00493的博客 457

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Dubbo源码分析(七)服务目录

前言 在上一章节的内容中,我们分析了服务引用的具体流程。在大多数情况下,为避免单点故障,我们的应用会部署在多台服务器上。对于我们的Dubbo而言,就会出现多个服务提供者。而且这些服务也并非是一成不变的,那么就有这样一个问题: 有新的服务提供者加入或者禁用、修改已有的服务提供者,那么服务消费者怎么及时感知它们的变化呢? 一、服务目录 或许你还有印象 ,在服务引用的时候,我们曾经有用到它。这个就是服务...

weixin_33705053的博客 171

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

STL源码分析目录

SIG STL源码分析 前言 本专栏主要以STL源码剖析分析路线来分析SIGSTL3.0源码. 整个模块准备对学习STL源码剖析之后做一个系统的总结, 这些都是我个人的理解, 如果分析有什么问题欢迎各位大佬们指出. 也很感谢作者以及网络中各个大佬的总结, 让我也能更容易更深刻的理解到STL强大和方便, 也让我对template感受深刻. 以下是我自己对STL版块进行分析. 总共分为六个版块 : 空...

啦啦啦 3637

F2FS源码分析系列文章目录

一、文件系统布局以及元数据结构 总体结构 Superblock区域 Checkpoint区域 Segment Infomation Table区域(SIT) Node Address Table区域(NAT) Segment Summary Area区域(SSA) 二、文件数据的存储以及读写 F2FS文件数据组织方式 一般文件写流程 一般文件读流程 目录文件读流程(未完成) 目录文件写流程(未完成) 三、文件与目录的创建以及删除(未完成) 一般文件的创建(未完成) 一般目录的创建(未完成) 一般文

Hubery的存储点滴 7412

JAVA源码解读---HashMap目录扩展的奥秘

摘要:为了探索JAVA1.7源码中HashMap类数据的组织方法与目录扩展方法,通过对JAVA1.7源码中HashMap类源码的阅读与分析,得出结论:hashmap中存储数据的数据结构采用的是链表数组,目录是个数组,数组的成员是链表。冲突解决方法:典型的链地址法,冲突后,在链表头部插入数据。目录扩展方法:已二倍的方式扩展,一直到目录的最大上限。目录扩展的触发条件:装载因子的方式触发。从java中hashmap的实现可以看出,桶数据的组织方式并不是一种非常高效的方式。对检索效率不利。同时,数据扩展简单的采用二

计算机技术博客 1965

《 Claude Code源码分析与实践》专栏目录

claw-code项目是一个结合Python和Rust的AI工程化实践,围绕30个关键技术方向展开深度研究。该项目从源码层面剖析了智能体开发的核心问题,包括清单管理、会话机制、权限设计、工具调用等基础架构,重点关注工程实践中的测试策略、状态管理、移植兼容性等挑战。研究覆盖了从命令行接口到服务端部署的全流程,特别探讨了在保持功能完整性的同时如何实现代码重构与架构迁移,以及大型项目中类型系统、错误处理和多语言协作等关键问题。这些研究方向既包含底层技术细节,又涉及产品化考量,为AI系统开发提供了可落地的工程方法论

数据知道的博客 1998

u-boot源码分析

Uboot源码分析 源码以u-boot-1.3.4为基准,主芯片采用at91sam9260,主要介绍uboot执行流程。 uboot官网:http://www.denx.de/wiki/U-Boot/WebHome。 一.工具 1. 主要采用vi查看源码,用到最多命令为grep。 grep –r –n ‘string’ ./* 搜索该目录及其以下包含string的文件并...

weixin_30642869的博客 102

算法与数据结构 — 结合 Java 源码分析数据结构

文章目录数据结构总结一、概念二、常见的数据结构1. 数组(Array)2. 链表(Linked List)3. 栈(Stack)4. 队列(Queue)5. 树(Tree)6. 图(Graph)7. 堆(Heap)8. 散列表(Hash table) 数据结构总结 一、概念 在计算机科学中,数据结构(英语:data structure)是计算机中存储、组织数据的方式。 数据结构意味着接口或...

pentiumCM的博客 585

3D打印机切片引擎CuraEngine源码分析<三> 系列目录

这篇博文时这个分析系列的目录,先写下来。希望自己能够完成这一整个系列的博客。 1. 3D打印机切片引擎CuraEngine源码分析  CuraEngine中的ReadMe解读,CuraEngine的版本介绍 2. 3D打印机切片引擎CuraEngine源码分析  CuraEngine文件目录分析 3. 3D打印机切片引擎CuraEngine源码分析  CuraEngine切片的流

Just 7686

深入探索Linux协议栈开发:从源码分析到主要数据结构

深入探索Linux协议栈开发:从源码分析到主要数据结构

深耕嵌入式领用多年, 致力于分享嵌入式领域技术! 862

HashMap源码分析

文章目录简介继承关系存储结构源码分析属性Node节点TreeNodeHashMap 构造方法put 添加方法待更新 简介 在我们对数据存储的时候都会有数据结构这种东西,但是传统的底层数据结构比如数组或链表,不够好用,所有一些大神就为我们对这些基础数据结构作了进一步的封装,有了更高级的数据结构,而HahsMap就是由此而来,HashMap采用key/value存储结构,每个key对应唯一的value。查询和修改的速度都很快,能达到O(1)的平均时间复杂度。它是非线程安全的,且不保证元素存储的顺序 继承关系

念念不忘,必有回响 5698
上一篇: MySQL浅谈
下一篇: Redis浅谈
Coder_Joker
博客等级 码龄8年 39粉丝 67原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值