Exponential-Golomb coding

参考资料:
http://en.wikipedia.org/wiki/Exponential-Golomb_coding
http://zh.wikipedia.org/zh/指数哥伦布码
Information technology — Coding of audio-visual objects — Part 10: Advanced Video Coding

摘抄自以上资料,简单总结。

指數哥倫布碼(Exp-Golomb code),一种壓縮編碼方法。
用来表示非负整数的k阶指数哥伦布码可用如下步骤生成:
1. 将数字以二进制形式写出,去掉最低的k个比特位,之后加1
2. 计算留下的比特数,将此数减一,即是需要增加的前导零个数(注意是比特位数,非该比特串表示的值)
3. 将第一步中去掉的最低k个比特位补回比特串尾部
0阶指数哥伦布码如下所示:

0 => 1 => 1
1 => 10 => 010
2 => 11 => 011
3 => 100 => 00100
4 => 101 => 00101
5 => 110 => 00110
6 => 111 => 00111
7 => 1000 => 0001000
8 => 1001 => 0001001
...

从二进制比特串形式来看,0阶哥伦布编码的码字(codeword)由3部分构成:
码字 = [M个0] + [1] + [内容]
内容也是M位数据,所以每个0阶哥伦布码的位的长度为2M + 1,每个码字由原始的数字(codenumber)产生。

比如上面的数字7,二进制表示为111,0阶编码,所以不用去最后的比特为,加1之后变成1000,比特数为4位,所以前缀需要增加3(4-1)个0,即0001000,0阶所以结尾也不需要补码,于是最终码字就为0001000。

那如何解码呢?
参见如下伪代码

leadingZeroBits = −1
for (b = 0; !b; leadingZeroBits++)
	b = read_bits(1)

codeNum = 2^(leadingZeroBits + k) − 2^k + read_bits(leadingZeroBits + k)

这里类似于2^k这种写法表示幂运算,对于通常H.264当中用的是0阶的,所以可以简化成如下图

Exponential-Golomb Decoding

这里read_bits(…)的返回值使用高位在先的二进制无符号整数表示

二进制比特串       长度             解析值
1001             1               0
001 1001         5               5
01 1010          3               2
010              3               1
000 1011         7               10
0001 001         7               8

如上表,传入的比特串可能多余实际需要的数据,我们只需要解析需要的部分就可以了。

P.S.
为什么叫做指数哥伦布编码?
因为它对信源符号的分组大小按照指数增长。

二叉树

炒现饭的帖子,内容均来自于网络或者书籍整理。

I)树
它是由N(N>=1)个有限结点组成一个具有层次关系的集合,它具有以下的特点:
a)每个结点有零个或多个子结点,没有子节点的节点称为叶节点(通常称为叶子)
b)没有父结点的结点称为根结点(通常称为根)
c)每一个非根结点有且只有一个父结点(没有多个引用指向同一个节点)
d)除了根结点外,每个子结点可以分为M个不相交的子树

|
r        55
o       /  \
o      /    \
t     88     3
.           /|\
.          / | \
.         67 7 23
l        / \     \
e       /   \     \
a      53    5     9
f
|

        Figure. A

如上图(Figure. A),它像一棵自然界中倒生长的树,每个枝丫处就是一个节点,方向是由根到叶子,它实际上是一个有向图。

这里我们介绍下节点,节点是包含一个数据项和一个(多个)指向其他节点的引用项的数据结构/记录,通常我们用类似如下代码来表示一个节点:
1)

record SinglyLinkedNode {
    next, // A reference to the next node
    data // Data or reference to data
}

2)

record DoublyLinkedNode {
    previous, // A reference to the previous node
    next, // A reference to the next node
    data // Data or reference to data
}

3)

record BinaryNode {
    parent, // A reference to the parent node                                
    left_child, // A reference to the left child node
    right_child, // A reference to the right child node
    data // Data or reference to data
}

结合上图(Figure. A)我们就很好理解了。

一些有关树的基本概念:
节点的度(node’s degree): 子节点的个数叫做节点的度
树的度: 一棵树中,最大的节点的度称为树的度
节点层次(level): 根为第一层,根的子节点为第二层,以此类推
数的高度或深度(depth): 树中最大的节点层次
兄弟节点(siblings): 具有相同父节点的节点
森林: M(M>=0)棵互不相交的树的集合(删去一棵树的根,就得到一个森林;加上一个结点作树根,森林就变为一棵树)
有序树(ordered tree)/无序树(unodered tree): 若将树中每个结点的各子树看成是从左到右有次序的(即不能互换),则称该树为有序树(ordered tree);否则称为无序树(unodered tree)
还有诸如子孙/祖先/堂兄弟节点这些概念就不列举了

上图(Figure. A)当中,树的度是3,67节点的度是2,数的深度是4,55节点是根节点等等这些基本属性我们就能很快得出。

II)二叉树
每个结点最多有两个子树的有序树,通常有左子树(left subtree)和右子树(right subtree),最大的节点的度为2,也就是二叉树的度为2。

满二叉树(full binary tree): 有时被称为proper binary tree或者2-tree或者strictly binary tree,就是每个节点有0或2个子节点。

完全二叉树(complete binary tree): 除了最后一层之外的其他层次(当然也可能包含最后一层),每个节点都包含2个子节点,并且所有节点都尽可能靠左排列

平衡二叉树: 如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树

二叉树的遍历,前序(pre-order),中序(in-order)和后序(post-order),前序是根左右,中序是左根右,后序是左右根。

一些有关二叉树的常用算法参看http://blog.csdn.net/luckyxiaoqiang/article/details/7518888

几个简单的例子:

这里的代码实现都是简单易懂的实现,帮助理解概念,没有做过优化!

参考资料:
http://en.wikipedia.org/wiki/Tree_(data_structure)
http://en.wikipedia.org/wiki/Node_(computer_science)
http://en.wikipedia.org/wiki/Branching_factor
http://en.wikipedia.org/wiki/Binary_tree

http://zhedahht.blog.163.com/blog/static/25411174201142733927831/

Java知识脉络

Java知识庞大而复杂,所以有必要标记下自己学过哪些东西,让自己更清楚

Java Language Partition

I 基本数据类型引用类型

String
常量池(Constant Pool)存在于.class文件中,运行时被加载,可以扩充,String.intern()方法就可以扩充常量池

String变量是有长度限制的,最大长度为Integer.MAX_VALUE
但String常量(string literals)的最大长度却不为这么多,参考地(http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#7963)和

关于

String s = new String("hello");

创建几个对象的问题,参见这里

会有字符串对象只在Heap中,但是Constant Pool中不存在对应的字面表示吗?Constant Pool中的内容会不会被GC?

II 常用对象

III

IV

V

VI

VII 一些错误或者异常
java.lang.OutOfMemoryError: Requested array size exceeds VM limit

VIII

Java Virtual Machine Partition

I Feature
Stack based
Symbolic reference
Garbage collection
Explicitly defining the primitive data type
Network byte order

II Class Format
Methods in Java are restricted to 64k
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4309152

III GC
根集合是什么,怎么确定根集合?
HotSpot虚拟机中垃圾对象的扫描是采用的路径搜索方法,从根集合开始没有路径可到达的被认为是垃圾对象,可以回收
根集合包括,栈帧当中

IV Instruction Set
invokeinterface: Invokes an interface method
invokespecial: Invokes an initializer, private method, or superclass method
invokestatic: Invokes static methods
invokevirtual: Invokes instance methods

PS.
update 2012-02-09 写的这个破玩意在草稿箱躺了6个月了,发出来边看,边补充吧。

IO,Network,Protocol等等标记帖

这里都是一些感觉写的好或着写的明白的经典内容

IO
IO – 同步,异步,阻塞,非阻塞 (亡羊补牢篇)
http://blog.csdn.net/historyasamirror/article/details/5778378

HTTP
深入理解HTTP协议(转)
http://www.blogjava.net/zjusuyong/articles/304788.html

TCP
位码即TCP标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)
Sequence number(顺序号码) Acknowledge number(确认号码)

TCP状态表
CLOSED
LISTEN
SYN RCVD
SYN SENT
ESTABLISHED
FIN WAIT 1
FIN WAIT 2
TIME WAIT (双方均已断开)
CLOSING
CLOSE WAIT (被动关闭)收到对方关闭请求,并且已经确认
LAST ACK (被动关闭)等待最后一个关闭确认

建立连接过程
一般情况是服务端执行LISTEN原语进入LISTEN(被动打开)状态
客户端发出CONNECT命令,创建报文段(带SYN)并发送,进入SYN SENT状态
服务端收到一个SYN报文段,给客户端回应ACK同时发送一个SYN,进入SYN RCVD状态
客户端收到SYN+ACK报文段,并发送三次握手的最后一个ACK报文段,进入ESTABLISHED状态
服务端收到确认的ACK报文段,完成三次握手,进入ESTABLISHED状态

关闭连接过程
客户端执行CLOSE原语,创建报文段(带FIN)并发送,进入FIN WAIT 1状态
服务端收到一个FIN报文段,确认客户端的请求并回发一个ACK报文段,进入CLOSE WAIT状态
客户端收到服务端的确认ACK报文段,转移到FIN WAIT 2状态,此时从客户端到服务器方向的连接已经断开
服务端应用得到通告后,执行CLOSE原语,创建报文段(带FIN)并发送,进入LAST ACK状态
客户端收到FIN报文段并确认,进入TIME WAIT状态,此时双方连接均已经断开
但TCP要等待一个2倍报文最大生存时间(2MSL),确保。。。,到超时时间后,删除记录,进入CLOSED状态
服务端收到最后一个ACK报文段,释放连接,删除记录,进入CLOSED状态

http://www.cs.berkeley.edu/~kfall/EE122/lec23/sld001.htm
Three-way handshake
– A ——> Seq k, SYN ——> B
– A <--- Seq j, ACK k + 1, SYN + ACK <--- B - A ----> Seq k + 1, ACK j + 1, ACK —->

Four-way handshake
– A —- Seq k, ACK j + 1, FIN + ACK —-> B
– A <--- Seq j, ACK k + 1, ACK <--- B - ... sometime later ... - A <--- Seq j, ACK k + 1, FIN + ACK <--- B - A ---> Seq k, ACK j + 1, ACK —>

Wireshark真实抓包数据
三次握手

33	44.679312	192.168.1.102	58.215.40.94	TCP	53902 > smtp [SYN] Seq=0 Win=5840 Len=0 MSS=1460 TSV=3199582 TSER=0 WS=6
34	44.761376	58.215.40.94	192.168.1.102	TCP	smtp > 53902 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1440 TSV=1575891196 TSER=3199582 WS=7
35	44.761442	192.168.1.102	58.215.40.94	TCP	53902 > smtp [ACK] Seq=1 Ack=1 Win=5888 Len=0 TSV=3199602 TSER=1575891196

四次分手

181	279.133008	192.168.1.102	58.215.40.94	TCP	59658 > smtp [ACK] Seq=7 Ack=93 Win=5888 Len=0 TSV=3258195 TSER=1576125611
182	279.133545	58.215.40.94	192.168.1.102	TCP	smtp > 59658 [FIN, ACK] Seq=93 Ack=7 Win=5888 Len=0 TSV=1576125611 TSER=3258186
183	279.133630	192.168.1.102	58.215.40.94	TCP	59658 > smtp [FIN, ACK] Seq=7 Ack=94 Win=5888 Len=0 TSV=3258195 TSER=1576125611
186	279.264675	58.215.40.94	192.168.1.102	TCP	smtp > 59658 [ACK] Seq=94 Ack=8 Win=5888 Len=0 TSV=1576125739 TSER=3258195

http://blog.chinaunix.net/space.php?uid=20587912&do=blog&cuid=2201855
http://wenku.baidu.com/view/2fd4a6d126fff705cc170af3.html
OSI 7层协议
物理层
数据链路层
网络层
传输层
会话层
表示层
应用层

TCP 4层协议
网络接口层(ARP,RARP…)
网间层(ICMP,IP)
传输层(TCP,UDP)
应用层(SMTP,HTTP,FTP,DNS)

面试题之多线程数组求和

想换工作的,平时还是要做些面试题,因为冷不丁的被面一下,会感觉突然,当然结果也是很糟糕。
这是一道老题目“一个非常非常大的int类型数组,用多线程计算和。假设数组长度M线程数量N”。
思想是分而治之,跟快速排序MapReduce思想有些类似。

这里是一个实现的一个简单版本,根据有多少线程,然后把数组分为多少段,因为求和的过程都是读取数组元素,涉及不到锁等等。
所以只要段划分正确,计算就是简单的事情了。

有空再来用Future实现一个版本

原码,反码,补码备忘

又是一篇炒现饭的帖子,主要是经常忘记,记在这里

首先理解位bit(Binary digit http://en.wikipedia.org/wiki/Bit)

以下都以二进制为例

比如一个8位的存储单元,那么它就可以保存256种不同状态,如果是无符号数的话,那么就是0 ~ 2^8-1,即00000000 ~ 11111111

那么对于有符号的数就是-2^7 ~ 2^7-1,最高位拿来存储符号了,0为正,1为负,即10000001 ~ 01111111

十进制 原码 反码 补码
127 01111111 01111111 01111111
-127 11111111 10000000 10000001
128 010000000 010000000 010000000
-128 10000000
45 00101101 00101101 00101101
-45 10101101 11010010 11010011
1 00000001 00000001 00000001
-1 10000001 11111110 11111111

上表中红色的数是表示溢出的,8位的存储空间无法表示这样的有符号数

计算机中的有符号数都是以补码的形式存放的,可以理解为只有有符号数才有原码,反码,补码
正数的原码,反码,补码表示都一样
负数的原码为其绝对值的原码,但符号位为1;反码就是保持原码的符号位不变,其他位按位取反;补码就是反码加1

引用Wikipedia
“一个数字的二补数就是将该数字作位反相运算(即一补数),再将结果加 1,即为该数字的二补数。”

为什么要引入原码,反码,补码这些概念
参见:http://dev.csdn.net/htmls/17/17680.html

我们最需要关注的是补码,引用作者的原话是

补码的设计目的是:
⑴使符号位能与有效值部分一起参加运算,从而简化运算规则
⑵使减法运算转换为加法运算,进一步简化计算机中运算器的线路设计

引用自http://zh.wikipedia.org/wiki/二補數
在二补数系统中,一个负数就是用其对应正数的二补数来表示。
00000100 4
11111011 按位取反
11111100 二补数(-4)

减法可以用一个数加上另一个数的二补数来表示
5
-4
———-
1

00000101
+11111100
———-
000000001

另外字节(Byte),字(Word),双字,四字,字长这些概念都需要理解

阮一峰有个帖子讲的也很清楚明了

参考

http://zh.wikipedia.org/wiki/原码
http://zh.wikipedia.org/wiki/反码
http://zh.wikipedia.org/wiki/二補數
http://en.wikipedia.org/wiki/One’s_complement
http://en.wikipedia.org/wiki/Two’s_complement