显示标签为“算法”的博文。显示所有博文
显示标签为“算法”的博文。显示所有博文

2012年7月27日星期五

Dijkstra 算法

Dijkstra's algorithm
     -- 贪婪技术的一种经典算法,戴克斯特拉算法(维基说法

# 算法逻辑
算法描述 Dijkstra (G, s)
          // 单起点最短路径的Dijstra算法
          // 输入: 具非负权重加权连通图 G = < V, E> 以及它的顶点s
          // 输出: 对于V中的每一个顶点v来说, 从s到v的最短路径的长度dv
          // 以及路径上的倒数第二个顶点pv
          Initialize(Q)     // 将顶点优先队列初始化为空
          for V中每一个顶点 v do
               dv = -1; pv = null;
               Insert(Q, v, dv);     // 初始化优先队列中顶点的优先级
          ds = 0; Decrease(Q, s, ds);
          Vt = {} // 初始化为空
          for i = 0 to |V| - 1 do
               u* = DeleteMin(Q);     //删除优先级最小的元素
               Vt = Vt + { u* };
               for V - Vt 中每一个和u*相邻的顶点u do
                    if du* + w(u*, u) < du
                         du = du* + w(u*, u);
                         pu = u*;
                         Decrease(Q, u, du);

# 算法效率
分析该算法的时间复杂度,假设对应的连通图边数 m 和顶点数 n 。
1, 最简单实现方法,以一个链表或者数组来存储所有顶点的集合Q,而搜索Q中权值最小元素操作DeleteMin只需线性搜索为复杂度O(n)。该算法整体的时间复杂度是 O(n^2)。

2, 用邻接表来更有效的实现该算法,同时以二叉树结构作为优先队列存Q,则搜索权值最小元素DeleteMin时间复杂度为Q(log n),此时该算法整体的时间复杂度为O((m + n)log n),

# 示例说明
(还是伪码,从代码提炼出来的伪码,这样看起来应该比较浅显易懂。)
void Dijkstra (Graph& G)
{
Queue Q; Path P;
InitQueuePath(Q, P);
for (int s=0; s< G.points;s++) {
Decrease(Q, s, 0);
for (int i=0; i < G.points-1; i++) {
int u = DeleteMin(Q, G.flag, G.points);
if (u==-1)
break;

for (int j=0; j< G.points; j++) {
if ( G.flag[j]==false && ((__int64)Q[u]+G.A[u][j])<Q[j]) {
P[j] = u;
Decrease(Q, j, Q[u]+G.A[u][j]);
}
}
}
for (int i=0; i < G.points; i++)
G.A[i][s] = G.A[s][i] = Q[i];
}
}

完整的C++示例代码存放在github

# 引用扩展

参见维基上伪码描述如下:

在下面的算法中,u := Extract_Min(Q) 在顶点集合 Q 中搜索有最小的 d[u] 值的顶点 u。这个顶点被从集合 Q 中删除并返回给用户。

function Dijkstra(G, w, s)
     for each vertex v in V[G]                        // 初始化
             d[v] := infinity                         // 将各点的已知最短距离先设置成无穷大
             previous[v] := undefined                 // 各点的已知最短路径上的前趋都未知
     d[s] := 0                                        // 因为出发点到出发点间不需移动任何距离,所以可以直接将s到s的最小距离设为0
     S := empty set
     Q := set of all vertices
     while Q is not an empty set                      // Dijkstra演算法主體
             u := Extract_Min(Q)
             S.append(u)
             for each edge outgoing from u as (u,v)
                      if d[v] > d[u] + w(u,v)         // 拓展边(u,v)。w(u,v)为从u到v的路径长度。
                              d[v] := d[u] + w(u,v)   // 更新路径长度到更小的那个和值。
                              previous[v] := u        // 记录前趋顶点

如果我们只对在 s 和 t 之间寻找一条最短路径的话,我们可以在第9行添加条件如果满足 u = t 的话终止程序。
通过推导可知,为了记录最佳路径的轨迹,我们只需记录该路径上每个点的前趋,即可通过迭代来回溯出 s 到 t 的最短路径(当然,使用后继节点来存储亦可。但那需要修改代码):
 s := empty sequence 
 u := t
 while defined u                                        
       insert u to the beginning of S
       u := previous[u]      //previous数组即为上文中的p
现在序列 S 就是从 s 到 t 的最短路径的顶点集。

关于“Dijkstra 算法”更详细的文字描述可以参见维基百科百度百科

2012年7月9日星期一

内存的分配与回收(笔记)


内存的分配与回收
     -- =(内存管理)分区的分配与回收

1. 固定分区时的分配与回收。
     关键点,需要一张描述不用分区使用情况的分区说明表。
     分配时,只要存储管理程序根据请求查询分区说明表(或链表),从中找出一个满足要求的空闲分区,将其分配给申请者。
     回收时,操作就更简单了,不需要内存资源了,管理程序只要将对应的分区状态置为为使用即可。

2. 动态分区时的分配与回收。
     不同于固定分区方案,该方案需主要解决三个问题:
     1)分配程序(算法),从分区表寻找(最)合适的空闲分配出去。
     2)分配之后,更新分区表。
     3)回收算法,回收(释放)分区时需和相邻的空闲区进行链接合并,更新分区表。

     分配算法有三种常用算法包括最先适应法(first fit algorithm),最佳适应法(best fit algorithm)和最坏适应法(worst fit algorithm)。

     a. 最先适应法,要求分区表(表或自由链表)按起始地址递增的次序排列。该算法的最大特点是一旦找到大于或等所要求内存长度的分区则结束搜索。接着,从找到的分区划分要求的长度分配出去,并把余下部分与相邻分区合并(若相邻空闲区存在的话),更新分区表。
          1. 搜索分区表空闲区大小大于或等于申请大小alloc_size,若找到则继续2,否则停止分配失败;
          2. 找到合适空闲区A,若其大小a_size==alloc_size,直接标记分区A为“使用区”完成。
          3. 若a_size > alloc_size,切分A为A1(alloc_size),A2(a_size-alloc_size),标记A1“使用区”,A2“空闲区”。

     b. 最佳适应法,从分区表寻找最合适的空闲区分配。这里的最合适标准可以认为是空闲区的大小与要求的大小相差最小。
          1. 遍历分区表找最接近于申请大小alloc_size空闲区B,若找到则继续2,否则停止分配失败;
          2. 找到最合适空闲区B,若其大小b_size==alloc_size,直接标记分区A为“使用区”完成。
          3. 若b_size> alloc_size,切分B为B1(alloc_size),B2(b_size-alloc_size),标记B1“使用区”,B2“空闲区”。

   c. 最坏适应法,从分区表寻找最大的空闲区分配。
          1. 遍历分区表找最大空闲区W,大小为w_size,若w_size >alloc_size则继续2,否则停止分配失败;
          2. 找到最合适空闲区W,若其大小w_size==alloc_size,直接标记分区A为“使用区”完成。
          3. 若w_size> alloc_size,切分W为W1(alloc_size),W2(w_size-alloc_size),标记W1“使用区”,W2“空闲区”。

     (详细介绍可从网络搜索参考资料)


3. 几种分配算法的比较

     a. 从搜索速度上看,最先适应算法具有最佳性能。另一个有点就是尽可能地利用了低地址空间,从而保证高地址有较大的空闲区来放置要求内存较多的进程或作业。
     b. 最佳适应法找到的空闲区是最佳的,最合适用户要求的可用空闲区。但这样做在某些情况下并不一定提高内存的利用率。倒是可能导致内存碎片更多,因为分区表可能剩下越来越多的“小碎片”不能满足后续使用。
     c. 最坏适应算法正是基于不留碎片空闲区这点出发的,它选择最大空闲区来满足申请的要求,以期分配后的剩余部分仍能后续分配使用。


最后,总之三种算法各有特长,针对不同的请求队列,效率和功能不一样。实际项目开发使用,可以适度地多者结合一起使用。

……

(完)

2012年7月3日星期二

两种优先搜索算法

两种优先搜索(查找)算法
     -- 深度优先 & 广度优先 (经典算法

> 描述
”如果说深度优先查找遍历表现出来的是一种勇气(该算法尽可能地“离家”远些),广度优先查找遍历表现出来的则是一种谨慎。“

好吧,具体两种优先搜索算法逻辑描述,如下:
 1, DFS -- 深度优先搜索
 2, BFS -- 广度优先搜索


> 算法

 DFS(G)

 // 实现给定图的深度优先查找遍历
 // 输入: 图 G = <V, E>
 // 输出: 图G的顶点, 按照被DFS遍历第一次访问到的先后次序, 用连续的整数标记.
 V = { 0 } // 将V包含顶点标记为0, 表示均未访问状态.
 count = 0;
 for each vertex v in V do
if v is marked with 0
dfs(v)

dfs(v)
 // 递归访问所有和v相连接的未访问的顶点, 然后按照全局变量 count的值
 // 根据遇到它们的先后顺序, 给它们赋上相应的数字
 count +=1;
 mark v with count
 for each vertex w in V adjacent to v do
 if w is marked with 0
  dfs (w);

 BFS(G)
 // 实现给定图的广度优先查找遍历
 // 输入: 图 G = <V, E>
 // 输出: 图G的顶点, 按照被BFS遍历第一次访问到的先后次序, 用连续的整数标记.
 V = { 0 } // 将V包含顶点标记为0, 表示均未访问状态.
 count = 0;
 for each vertex v in V do
if v is marked with 0
bfs(v)

bfs(v)
// 访问所有和v相连接的未访问的顶点, 然后按照全局变量 count的值
// 根据访问它们的先后顺序, 给它们赋上相应的数字
count +=1;
mark v with count and initialize a queue with v
while the queue is not empty do
for each vertex w in V adjacent to the front vertex v do
if w is marked with 0
 cout += 1;
 mark w with count
 add w to the queue
 remove the front vertex from the queue


> 对比
两种优先搜索算法,多方面因素对比表如下:

项目DFSBFS
数据结构栈(stack)队列(queue)
顶点顺序的种类两种顺序一种顺序
边的类型(无向图)树向边和回边树向边和交叉边
应用连通性/无环行/关节点连通性/无环性/最少边路径
邻接矩阵的效率O (|V|^2)O (|V|^2)
邻接链表的效率O (|V| + |E|)O (|V| + |E|)




> 参考
A.
  文章描述包含有引用自《算法设计与分析基础(第2版)》涉及的章节内容
B.
  二叉树的两种优先搜索(遍历),示例C++程序代码参见 Github

void bfs_tree(treeT* tree);
void dfs_tree(treeT* tree);

还有,下面两道小算法题,可以借助深度优先搜索算法得到快速的求解。
a 简单栈的实现,前序遍历二叉树(深度优先搜索)。
b 关于二叉树,查找存在一条从根节点至叶子节点的路径的数值总和为Value。
     (结合深度优先搜索二叉树)

2012年6月28日星期四

一种特殊的排序算法 II



一种特殊的排序算法 II
  -- 计数排序(Counting sort)

后续想找时间再写一篇《一种特殊的排序算法 II》,关于计数排序☺。(引自 《一种特殊的排序算法 I》)

所以,继上篇文章《一种特殊的排序算法 I》,在此就(继续)描述,总结另一种特殊的排序算法,计数排序。算法的步骤如下:
  1. 找出待排序的数组中最大和最小的元素
  2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i
  3. 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
  4. 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

引用自维基内容,完整介绍可以参见计数排序(维基)

(后面,开始分享我的内容)
关于计数排序(算法),可以划分两种具体的计数法,如下:
 * 比较计数法
 * 分布计数法

===
> 比较计数法
算法 ComparisonCountingSort(A[0 ... n-1])
          // 用比较计数法对数组排序
          // 输入:可排序数组 A[0 ... n-1]
          // 输出:将A中元素按照升序排列的数组 S[0 ... n-1]
          for i : 0 to n-1 do 
               Count[i] = 0;
          for i : 0 to n-2 do
               for j : i+1 to n-1 do
                    if A[i] < A[j]
                         Count[j] += 1;
                    else
                         Count[i] += 1;
          for i : 0 to n-1 do
               S[Count[i]] = A[i];
          return S;

该算法的时间效率如何?答案为O(n^2)。因为该书法执行的键值比较次数和选择排序一样多,并且还占用了线性数量的额外空间,我们几乎不能推荐它来实际的应用。但是计数思想在一种情况下还是卓有成效的,在这种情况下,待排序的元素的值都来自于一个已知的小集合,这就是下面要描述的另一种计数排序算法,分布计算法。

===
> 分布计数法
算法 DistributionCountingSort(A[0 ... n-1, l, u])
          // 用分布计数法对数组排序,对来自于有限范围整数的一个数组进行排序
          // 输入:可排序数组 A[0 ... n-1],数组中的整数位于l和u之间( l <= u)
          // 输出:将A中元素按照升序排列的数组 S[0 ... n-1]

          for i : 0 to u-l do 
               D[i] = 0;                       // 初始化频率数组
          for i : 0 to n-1 do 
               D[A[i] - l] = D[A[i] - l] + 1;  // 计算频率值
          for i : 1 to u-l do 
               D[i] = D[i-1] + D[i];           // 重用于分布值

          for i : n-1 downto 0 do 
               j = A[i] - l;
               S[D[j] - 1] = A[i];             // D[j] - 1]为对应的数组下标
               D[j] -= 1;

 
        return S;

注:频率值,表示元素出现的次数;分布值表示在最后有序数组中,元素最后一次出现的位置。


假设数组值的范围是固定的,这显然是一个线性效率的算法,因为它仅仅对输入数组A从头到尾连续处理两遍,其时间复杂度 O(n)。然而,要重点记忆的是,除了空间换时间之外,分布计数排序这种高效率是因为利用了输入列表独特的自然属性。

===
附:
文章内容乃学习心得(笔记),亦包括引用自《算法设计与分析基础(第2版)》内容(第七章时空权衡,7.1计数排序)。
以上描述的算法,以C\C++完成了简单的实现,示例代码参见 github


(完)

2012年6月26日星期二

一种特殊的排序算法 I


一种特殊的排序算法 I
     -- 位排序 OR 桶排序


绝大部分经典的排序算法,都是以元素间的比较为基础,如冒泡,选择,插入,快速,归并,堆排序等,虽然这些排序算法的时间和空间复杂度存在不同,但其算法平均时间复杂度均不超过O(n logn) (基数排序也比较特殊可做到O(k*n),详细对比情况可以参见维基排序算法
===

而下面内容描述的排序算法比较特殊,并非以元素间比较为基础的,其算法时间复杂度达到了O(n)。先来看看一道简单的示例题目吧(引用自:Google groups TopLanguage
   
特殊排序算法题目,如下:
     姓名集合names,名次集合ranks,按照名次顺序输出她们的名字,要求O(N)的时间复杂度。

解法如下: 
     解法一,不改变原来集合顺序,O(N)时间, O(N)空间。
     描述: 数组下标相当于姓名索引,新空间以名次顺序依次记录着姓名索引。

     解法二,在位重新排序,改变原来集合顺序,O(N)时间, O(1)空间。
     描述:每一次swap确定一元素的位置,最多总共N次swap能全部定位。


具体的程序设计(C/C++)代码在这里
===

有一种特殊的排序算法,在《编程珠玑I II》有讲述到的位排序(bitsort),也称桶排序
其实,上面的排序题目正是位排序的一种变种的应用,不知你是否已经发现了否?

位排序算法的整体思想,可以描述如下:
     1. 每字节有8bit(位),那么它就可标记8个连续的数,分别对应每bit位,若数值存在则对应bit位置为1。
     2. 把N个数分为1+N/8组(相当于有这么多个桶),每组标记连续的8个数。
     3. 申请(1+N/8)字节数组均初始化为0,遍历要排序的集合,存在的元素在对应的bit位标记1。
     标记规则: array[i/8] = (array[i/8] | (1<<(i%8)))
注:算法描述的字节亦可替换为整型类型,对应的比特位数字变为32。


===
关于位排序,同样可以瞄瞄其他网友描述,这里
后续想找时间再写一篇《一种特殊的排序算法 II》(20120629更新链接),关于计数排序☺。

(完)



2012年5月25日星期五

霍夫曼树一例(算法)

霍夫曼树一例(算法)
  -- Huffman-Tree应用一例



# Huffman-Tree
(搜集整理哈夫曼树理论知识)
给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman tree)。哈夫曼树又称为最优树。

霍夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的路径长度是从树根到每一结点的路径长度之和,记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。可以证明霍夫曼树的WPL是最小的。

此算法的思想是:
(1)设给定的一组权值为{W1,W2,W3,……Wn},据此生成森林F={T1,T2,T3,……Tn},F 中的没棵二叉树只有一个带权为W1的根节点(i=1,2,……n)。
(2)在F中选取两棵根节点的权值最小和次小的二叉树作为左右构造一棵新的二叉树,新二叉树根节点的权值为其左、右子树根节点的权值之和。
(3)在F中删除这两棵最小和次小的二叉树,同时将新生成的二叉树并入森林中。
(4)重复(2)(3)过程直到F中只有一棵二叉树为止。

霍夫曼树

                    

# 问题描述
     (源自于Google groups论坛讨论,转)

问题:把一块长度为L的木棒切成N块,每段的大小必须为a1,a2,…,an,每一次切木棒的代价为当前木棒的长度,完成切割任务的最小代价?


# 测试案例

Input
首先输入T,有T个测试用例
每个测试用例输入两行
第一行整数L和N。接下来一行是N个数表示每一段的木棒长度。
Output
求完成任务的最小代价

Sample Input
2
10 4
1 2 3 4
306 8
120 37 42 42 32 2 7 24
Sample Output
19
785
# 解决方案

霍夫曼树解法的确是一种“美妙”的解决方案啊。
我刚开始看到这问题倒没想到霍夫曼。倒是其他思路,解法一。

> 解法一:
(存在问题)
1 降序排序集合A{a1,a2,…,an} 。

2 遍历集合A,计算每次切木棒代价cost_i。针对前后相同的元素,ai==aj,特殊计算:
     先切出木棒2*a1,再从2*ai木棒对半切分。
 
3 以上切木棒过程,累加不同cost_i,得到cost_sun即所求结果最小代价。


看似OK,跑了几个简单测试用例,包括上面的两个用例,均通过。不过想想觉得不太对劲。
可以猜想知道,对于复杂的测试案例结果就错误了。留给你稍微想想吧:-)

后来,实现了霍夫曼解法,对于比较复杂的案例,两种解法得到结果对比,终于可以明确解法一的不足地方了!

“反过来想每次合并是两段长度之和。于是就变成了Huffman问题了。”
“解释一下样例一,10分割为4和6,代价为10,6分割为3和3,代价为6,3分割为1和2,代价为3。总代价为10+6+3,即Huffman树中非叶节点的权值和。”

> 解法二:
1. 借助上述的霍夫曼算法,集合A {a1,a2,…,an}作为权值,构造霍夫曼树,即最优权值二叉树。
2. 累加所有非叶子节点的权值,即所求的结果最小代价。


# 链接



2012年4月12日星期四

最佳的随机集合算法?


最佳的随机集合算法?

# 背景说明
 随机初始化集合元素。即经过某一随机算法初始化之后,集合元素顺序被打乱,呈现一种新的随机排列状态。

# 算法描述

1. 适用于元素个数大于1的集合 set[1 ... n] (n > 1) ,并初始化随机范围为集合元素个数size。
2. 从集合中随机一个元素与最后的元素交换,swap(set[rand_i], set[size]),rand_i = rand() % size + 1。
3. 缩小集合的随机范围,size = size - 1。
4. 继续步骤2、3,直至随机范围size缩小至1,则随机集合操作完毕。

相比STL随机初始化函数的实现,详见后续random_shuffle说明,这样做的好处为:
     保证每个元素被初始化的次数不超过1,即以上算法随机选出的各元素均不同,各元素被随机次数为1,而STL算法可能超过1次。

两者相同点,即随机次数均为n-1,n为元素个数。

# 示例代码说明

/// 随机派发集合元素
template <typename T>
void RandAssignElement(vector<T>& vecAll, vector<T>& vecRes)
{
    if (vecAll.size() > 1)
    {
        vecRes.assign(vecAll.begin(), vecAll.end());
        for (size_t i = vecRes.size(); i > 1; --i)
        {
            unsigned rand_i = rand() % i;
            std::swap(vecRes[rand_i], vecRes[i-1]);
        }
    }

}
/// 应用于扑克随机发牌情况!
static void TestPokerLicensing()
{
    vector<unsigned> vecAll(54);
    for (size_t i = 0; i < vecAll.size(); ++i)
        vecAll[i] = (i + 1);
    vector<unsigned> vecRes;
    RandAssignElement(vecAll, vecRes);

    printf ("print vecRes:\n");
    for (size_t i = 0; i < vecRes.size(); ++i)
        printf(" %u", vecRes[i]);
    printf ("\n");
}


/// 随机派发集合元素
template <typename T>
void RandAssignElement(vector<T>& vecAll, vector<T>& vecRes)
/// 扑克发牌
static void TestPokerLicensing()

# 附STL随机算法
 STL算法random_shuffle(随机初始化集合)的实现。

     1. MS-STL版本(较复杂)
// TEMPLATE FUNCTION random_shuffle
template<class _RanIt, class _Diff>
inline void _Random_shuffle(_RanIt _First, _RanIt _Last, _Diff *)
{     // shuffle [_First, _Last)
const int _RANDOM_BITS = 15;     // minimum random bits from rand()
const int _RANDOM_MAX = (1U << _RANDOM_BITS) - 1;

_RanIt _Next = _First;
for (unsigned long _Index = 2; ++_Next != _Last; ++_Index)
     {     // assume unsigned long big enough for _Diff count
     unsigned long _Rm = _RANDOM_MAX;
     unsigned long _Rn = ::rand() & _RANDOM_MAX;
     for (; _Rm < _Index && _Rm != ~0UL;
          _Rm = _Rm << _RANDOM_BITS | _RANDOM_MAX)
          _Rn = _Rn << _RANDOM_BITS | _RANDOM_MAX;     // build random value

     std::iter_swap(_Next, _First + _Diff(_Rn % _Index));     // swap a pair
     }
}

template<class _RanIt>
inline void random_shuffle(_RanIt _First, _RanIt _Last)
{     // shuffle [_First, _Last)
if (_First != _Last)
     _Random_shuffle(_First, _Last, _Dist_type(_First));
}

     2. SGI-STL版本(较简单)

// Return a random number in the range [0, __n).  This function encapsulates
// whether we're using rand (part of the standard C library) or lrand48
// (not standard, but a much better choice whenever it's available).

template <class _Distance>
inline _Distance __random_number(_Distance __n) {
#ifdef __STL_NO_DRAND48
  return rand() % __n;
#else
  return lrand48() % __n;
#endif
}

// random_shuffle

template <class _RandomAccessIter>
inline void random_shuffle(_RandomAccessIter __first,
                           _RandomAccessIter __last) {
  __STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator);
  if (__first == __last) return;
  for (_RandomAccessIter __i = __first + 1; __i != __last; ++__i)
    iter_swap(__i, __first + __random_number((__i - __first) + 1));
}

     3. 其他STL版本random_shuffle
      …… (略过)
      

2012年4月5日星期四

Fwd: 一些有意思的算法代码

一些有意思的算法代码



2011年11月29日
发表评论阅读评论19,849 人阅读    

Keith Schwarz是一个斯坦福大学计算机科学系的讲师。他对编程充满了热情。他的主页上他自己正在实现各种各样的有意思的算法和数据结构,http://www.keithschwarz.com/interesting/, 目前这个网页上有88个(见下面的列表),但这位大哥要干135个,你可以看看他的To-Do List

从这个列表上,我们可以看到,他从去年7月份就在自己实现这些东西了,我把他实现的这些算法转过来,

  • 另一方面我希望这个事可以影响到一些正在学习编程的人。看看别人是怎么学习编程的,希望对你有借鉴作用。
Name Link Date Added Language Description
Binomial Heap (link) 7‑24‑2010 C++ An implementation of a binomial heap data structure for use as a priority queue.
Bounded Priority Queue (link) 7‑24‑2010 C++ An implementation of a priority queue with a fixed upper limit to its size..
Matrix (link) 7‑24‑2010 C++ A collection of classes for manipulating matrices.
VList (link) 8‑16‑2010 Java An implementation of the List abstraction backed by a VList.
Function Wrapper (link) 8‑16‑2010 C++ A C++ wrapper class around unary functions.
String (link) 8‑17‑2010 C++ An implementation of a string abstraction that uses the small string optimization.

nstream (link) 8‑31‑2010 C++ An stream class that sends and receives data over a network.
Snake (link) 8‑31‑2010 C++ An implementation of the game Snake with a rudimentary AI.
Mergesort (link) 9‑14‑2010 C++ An implementation of the mergesort algorithm.
Next Permutation (link) 10‑6‑2010 C++ An implementation of the next_permutation STL algorithm.
Interval Heap (link) 10‑17‑2010 Java An implementation of a double-ended priority queue using an interval heap.
Linear-Time Selection (link) 10‑18‑2010 C++ A deterministic, linear-time selection algorithm using the median-of-medians algorithm.
Heapsort (link) 10‑18‑2010 C++ An implementation of the heapsort algorithm.
Union-Find (link) 10‑19‑2010 Java An implementation of a disjoint-set data structure using a disjoint set forest.
Radix Sort (link) 10‑19‑2010 C++ An implementation of the radix sort algorithm.
Rational (link) 10‑23‑2010 C++ A data structure representing a rational number.
DPLL (link) 10‑23‑2010 Haskell An implementation of the DPLL algorithm for solving CNF-SAT.
Smoothsort (link) 10‑27‑2010 C++ An implementation of the smoothsort algorithm, an adaptive heapsort variant.
Extendible Array (link) 10‑28‑2010 Javadynamic array class with O(1) worst-case runtime lookup and append.
In-Place Merge (link) 10‑29‑2010 C++ An implementation of a merge algorithm that runs in-place.
Random Shuffle (link) 10‑29‑2010 C++ An algorithm for generating a random permutation of a set of elements.
Random Sample (link) 10‑29‑2010 C++ An O(n) time, O(1) space algorithm for randomly choosing k elements out of a stream with uniform probability.
Natural Mergesort (link) 10‑30‑2010 C++ An implementation of natural mergesort, an adaptive variant of mergesort.
Interpolation Search (link) 10‑31‑2010 C++ An implementation of the interpolation search algorithm.
Introsort (link) 10‑31‑2010 C++ An implementation of the introsort algorithm, a fast hybrid of quicksortheapsort, andinsertion sort.
Hashed Array Tree (link) 11‑3‑2010 Java An implementation of a dynamic array backed by a hashed array tree.
Recurrence Solver (link) 11‑13‑2010 C++ A fast algorithm for generating terms of a sequence defined by a linear recurrence relation.
Fibonacci Heap (link) 11‑15‑2010 Java An implementation of a priority queue backed by a Fibonacci heap.
Dijkstra’s Algorithm (link) 11‑16‑2010 Java An implementation of Dijkstra’s algorithm for single-source shortest paths.
Prim’s Algorithm (link) 11‑17‑2010 Java An implementation of Prim’s algorithm for computing minimum spanning trees.
Kruskal’s Algorithm (link) 11‑17‑2010 Java An implementation of Kruskal’s algorithm for computing minimum spanning trees.
Majority Element (link) 11‑17‑2010 C++ A fast, linear-time algorithm for finding the majority element of a data set.
Haar Transform (link) 11‑17‑2010 C++ A set of functions to decompose a sequence of values into a sum of Haar wavelets.
Argmax (link) 11‑19‑2010 C++ A pair of functions to compute the arg min or max of a function on some range.
Derivative (link) 11‑19‑2010 C++function object that approximates the derivative of a function.
Levenshtein Distance (link) 11‑19‑2010 C++ An algorithm for computing the Levenshtein distance between two sequences.
Skiplist (link) 11‑20‑2010 C++ An implementation of a skip list, a randomized data structure for maintaining a sorted collection.
van Emde Boas Tree (link) 11‑26‑2010 C++ An implementation of a sorted associative array backed by a van Emde Boas tree.
Cuckoo HashMap (link) 11‑27‑2010 Java An implementation of a hash table using cuckoo hashing.
Needleman-Wunsch Algorithm (link) 11‑28‑2010 C++ An implementation of the Needleman-Wunsch algorithm for optimal string alignment.
Treap (link) 11‑28‑2010 C++ An implementation of a sorted associative array backed by a treap.
Floyd-Warshall Algorithm (link) 12‑10‑2010 Java An implementation of the Floyd-Warshall algorithm for all-pairs shortest paths in a graph.
Power Iteration (link) 12‑10‑2010 C++ An implementation of the power iteration algorithm for finding dominant eigenvectors.
Edmonds’s Matching Algorithm (link) 12‑15‑2010 Java An implementation of Edmonds’s matching algorithm for finding maximum matchings in undirected graphs.
Kosaraju’s Algorithm (link) 12‑15‑2010 Java An implementation of Kosaraju’s algorithm algorithm for finding strongly connected components of a directed graph.
2-SAT (link) 12‑15‑2010 Java A linear-time algorithm for solving 2-SAT.
Bellman-Ford Algorithm (link) 12‑17‑2010 Java An implementation of the Bellman-Ford algorithm for single-source shortest paths.
Topological Sort (link) 12‑17‑2010 Java An algorithm for computing a topological sort of a directed acyclic graph.
Graham Scan (link) 12‑19‑2010 C++ An implementation of the Graham scan for finding convex hulls in 2D space.
Bipartite Testing (link) 12‑19‑2010 Java A linear-time algorithm for checking whether a directed graph is bipartite.
Johnson’s Algorithm (link) 12‑19‑2010 Java An implementation of Johnson’s algorithm for all-pairs shortest paths.
Strassen Algorithm (link) 12‑20‑2010 C++ An implementation of the Strassen algorithm for fast matrix multiplication.
Cartesian Tree Sort (link) 12‑21‑2010 C++ An implementation of Cartesian tree sort, an adaptive, out-of-place heapsort variant.
Ford-Fulkerson Algorithm (link) 12‑21‑2010 Java An implementation of the Ford-Fulkerson maximum-flow algorithm.
Scaling Ford-Fulkerson (link) 12‑22‑2010 Java An modification of the Ford-Fulkerson maximum-flow algorithm that uses scaling to achieve polynomial time..
Splay Tree (link) 12‑27‑2010 C++ An implementation of a sorted associative array backed by a splay tree.
Ternary Search Tree (link) 12‑28‑2010 C++ An implementation of a sorted set of strings backed by a ternary search tree.
Ring Buffer (link) 12‑30‑2010 Java An implementation of a FIFO queue using a ring buffer.
AVL Tree (link) 12‑30‑2010 C++ A sorted associative container backed by an AVL tree.
Rabin-Karp Algorithm (link) 1‑1‑2011 C++ An implementation of the Rabin-Karp algorithm for string matching.
RPN Evaluator (link) 1‑18‑2011 C++ / strain A library to tokenize and evaluate simple arithmetic expressions in reverse Polish notation.
Shunting-Yard Algorithm (link) 1‑18‑2011 C++ / strain An implementation of Dijkstra’s shunting-yard algorithm for converting infix expressions to reverse-Polish notation.
Skew Binomial Heap (link) 1‑20‑2011 C++ An implementation of a priority queue backed by a skew binomial heap.
2/3 Heap (link) 3‑1‑2011 C++ An implementation of a priority queue whose branching factor alternates at different levels to maximize performance.
Zeckendorf Logarithm (link) 3‑10‑2011 C++ An algorithm based on Zeckendorf representations that efficiently computes logarithms.
Factoradic Permutations (link) 3‑17‑2011 C++ A set of algorithms for generating permutations using the factoradic number system.
Binary Cyclic Subsets (link) 3‑20‑2011 C++ A set of algorithms for generating subsets in lexicographical order using binary numbers and cyclic shifts.
Fibonacci Iterator (link) 3‑22‑2011 C++ An STL-style iterator for iterating over the Fibonacci numbers.
Fibonacci Search (link) 3‑22‑2011 C++ An implementation of the Fibonacci search algorithm.
Euclid’s Algorithm (link) 4‑18‑2011 Haskell An implementation of Euclid’s algorithm and applications to continued fractions and the extended Euclidean algorithm.
Find Duplicate (link) 4‑18‑2011 Python An algorithm to find a repeated element in an array using Floyd’s cycle-finding algorithm.
Permutation Generator (link) 4‑19‑2011 Pythongenerator for producing all permutations of a list of elements.
Matrix Find (link) 4‑19‑2011 Python A solution to the classic interview question of searching a sorted matrix for a particular value.
Binary GCD (link) 4‑23‑2011 Scheme An implementation of the binary GCD algorithm for computing greatest common divisors of nonnegative integers.
Knuth-Morris-Pratt Algorithm (link) 5‑3‑2011 Python An implementation of the Knuth-Morris-Pratt algorithm for fast string matching.
Kadane’s Algorithm (link) 5‑7‑2011 C++ An implementation of Kadane’s algorithm for solving the maximum-weight subarray problem.
Karatsuba’s Algorithm (link) 8‑15‑2011 Python An implementation of Karatsuba’s algorithm for fast integer multiplication.
Min-Stack (link) 8‑15‑2011 C++ An implementation of a LIFO stack that supports O(1) push, pop, and find-minimum.
Random Bag (link) 8‑15‑2011 Python A data structure that supports insertion and removal of a uniformly-random element.
Min-Queue (link) 8‑15‑2011 C++ An implementation of a FIFO queue that supports O(1) push, pop, and find-minimum.
Lights-Out Solver (link) 8‑29‑2011 C++ A solver for the game Lights Out using Gaussian elimination over GF(2).
Maximum Single-Sell Profit (link) 11‑9‑2011 Python Four algorithms for the maximum single-sell profit problem, each showing off a different algorithmic technique.
Generalized Kadane’s Algorithm (link) 11‑10‑2011 C++ A generalization of Kadane’s algorithm for solving the maximum subarray problem subject to a length restriction.
Longest Range (link) 11‑19‑2011 Java An algorithm for solving the longest contiguous range problem.
Egyptian Fractions (link) 11‑20‑2011 Python An implementation of the greedy algorithm for finding Egyptian fractions.
LL(1) Parser Generator (link) 11‑21‑2011 Java An LL(1) parser generator.
LR(0) Parser Generator (link) 11‑23‑2011 Java An LR(0) parser generator.
Word Ladders (link) 11‑27‑2011 JavaScript A program for finding word ladders between two words.

(全文完)

- - - - - - - - - - - -
谢谢,祝你快乐!(自动添加邮件末尾签名)

Junkun Huang
-- EOF --