首页 > 编程知识 正文

odoo源码分析,redis源码分析

时间:2023-05-04 22:56:26 阅读:249405 作者:3289

JAVA Queue

第一篇博客,希望以后每天坚持
目录:
1.Queue接口
2.Java中Queue接口方法
3.Queue的子类PriorityQueue分析
4.总结

1.Queue接口
数据结构中的队列,先进先出式的数据结构。
主要注意的时,Java中的Queue是比数据结构中理解的Queue更加灵活。这表现在:
a.数据结构中的Queue是按时间顺序的先进先出,即你先插入的元素总是先出的。但是JAVA中的Queue确实运行你实现自己的策略,确定什么元素是“优先”的,如它的value值模拟“它的达到时间”,value越大,则优先级越高,越排在前面。当前你也可以按照自然的常理的时间顺序。(注意:你确定了你的策略之后,就不可变了,不能一会说按照时间顺序,一会按照value倒叙)
b.比通常的queue多了一个方法peek,你可以查看却不删除,根据当前的值,觉得你的操作。

2.Java中Queue接口方法
六个:
a:add(E e):添加一个元素
b:remove():删除一个元素
c:offer(E e):添加一个元素
d:poll(E e):删除一个元素
f: element() :查看最上一个元素
h:peek():查看最上一个元素
上面六个函数总体上分为两类:安全的会进行容量检查的(add,remove,element),如果队列没有值,则取元素会抛出IlleaglStatementException异常。不安全的不进行容量控制的(offer,poll,peek )。

既然是这样,为什么要有两条语句相同的一个安全、不个不安全的呢?只提供一套安全的不久可以了么?

我的理解:有时候需要通过抛出异常来判断是容器中包涵null还是没有值。Queue通常不允许插入null值元素。但是有的实现却是允许插入null值的,如LinkedList.
另外,这里的分类不是严格的,并不是说所有queue的子类的add方法都会进行容量检查,然后抛出异常。这是要看容器的特性的,如Priorityqueue是无界的,add方法是直接的调用的offer方法。

3.Queue的子类PriorityQueue分析
3.1主要的方法成员
private static final int DEFAULT_INITIAL_CAPACITY = 11;
transient Object[] queue; // non-private to simplify nested class access

/** * The number of elements in the priority queue. */private int size = 0;/** * The comparator, or null if priority queue uses elements' * natural ordering. */private final Comparator<? super E> comparator;/** * The number of times this priority queue has been * <i>structurally modified</i>. See AbstractList for gory details. */transient int modCount = 0; // non-private to simplify nested class access

说明:PriorityQueue使用数组存储数据,基于数组形式的小根堆来做的。

3.2主要方法分析
a.构造方法

public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) { // Note: This restriction of at least one is not actually needed, // but continues for 1.5 compatibility if (initialCapacity < 1) throw new IllegalArgumentException(); //数组的大小,直接看用户指定的initialCapacity,没有指定就是默认值11 //区别于Map类型的,是2^n次方。 this.queue = new Object[initialCapacity]; this.comparator = comparator;}

注意:PriorityQueue是在构造函数调用阶段就已经申请了底层数组,而有的容器如HashMap是采用的懒加载机制,在实际的使用的时候,才会真正的去申请底层的数据空间(可能原因:hashmap是一个比较费空间的,因为来避免碰撞,获得较好的性能,则一般需要申请较大的底层数组,所以这种开销大的动作能推迟就推迟,而Queue在默认的没有指定初始容量的时候,只申请了长度为11的数组,开销较小。不过ArrayList在没有指定初始化容量的时候,也是采用的类似懒加载机制,指向一个长度为0的空数组,真正使用的时候才创建底层数组的空间,关于ArrayList其他的容器在以后再说)

b.添加元素
add方法:直接调用offer(E)方法
offer方法:
比较简单,因为priorityQueue是无界队列,所以,添加元素不会抛出illegalStateException异常。如果当前数组已满,则会直接扩容。
过程:
a:安全性检查,不运行插入null元素
b:容量检查,如果容量不够,则扩容。扩容原则:如果当前基层数组较小,则扩容时,每次扩展一倍。之后每次扩容时,每次扩展0.5倍
c.如果当前队列为空,则直接插入到queue[0]位置,不需要调整。否则,将元素直接“放到”一个有效位置上,然后调整,不断上浮。

public boolean offer(E e) { if (e == null) throw new NullPointerException(); modCount++; int i = size; if (i >= queue.length) grow(i + 1); size = i + 1; if (i == 0) queue[0] = e; else siftUp(i, e); return true;}

上浮函数:不断的为新节点找位置,最后找到位置后,才赋值一次。

private void siftUpComparable(int k, E x) {//父亲节点N,孩子节点2*N+1,2(N+1),则孩子节点编号k,父亲节点为(k - 1) >>> 1。0位置//也是存数据的 Comparable<? super E> key = (Comparable<? super E>) x; while (k > 0) { int parent = (k - 1) >>> 1; Object e = queue[parent]; if (key.compareTo((E) e) >= 0) break; queue[k] = e; k = parent; } queue[k] = key;}

c.删除元素
remove函数:主要还是调用的poll函数,只是增加了异常处理(属于装饰器模式么?)

public E remove() { E x = poll(); if (x != null) return x; else throw new NoSuchElementException();}

poll函数:
主要步骤:
a.容量检查
b.size标志减一,同时保存堆顶元素。
c.将最后一个元暂时提到堆顶位置,然后将堆顶元素调整,下移。

public E poll() { if (size == 0) return null; int s = --size; modCount++; E result = (E) queue[0]; E x = (E) queue[s]; queue[s] = null; if (s != 0) siftDown(0, x); return result;} private void siftDownComparable(int k, E x) { Comparable<? super E> key = (Comparable<? super E>)x; int half = size >>> 1; // loop while a non-leaf while (k < half) { int child = (k << 1) + 1; // assume left child is least Object c = queue[child]; int right = child + 1; //C为左右孩子中最小的 if (right < size && ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0) c = queue[child = right]; //如果key小于孩子,则不用调整的,否则,需要下移,孩子上移 if (key.compareTo((E) c) <= 0) break; //孩子上移 queue[k] = c; k = child; } queue[k] = key;}

d.清除元素
特别要注意的地方:要清楚引用,不能只是将size置位0,这样的话会造成内存泄漏

public void clear() { modCount++; //清楚引用,不能只是将size置位0,这样的话会造成内存泄漏 for (int i = 0; i < size; i++) queue[i] = null; size = 0;}

3.3其他
a.堆化函数
如果在构造PriorityQueue时,使用一个非priorityqueue集合初始queue,则策略是先将集合中的元素拷贝到底层的数组中,然后调用堆化函数调整元素顺序,使满足堆的性质。
过程:
调整非叶子点[0 , 2/size-1]之间的。

private void heapify() { for (int i = (size >>> 1) - 1; i >= 0; i--) siftDown(i, (E) queue[i]);}

4.总结
a:priorityqueue是无界队列
b:和其他集合容器一样,构造时,尽量大概估计容器大小
c:不允许null元素

marginUsinguseState()withanobjectasstate

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。