霍夫曼编码是一种基于最小冗余编码的压缩算法。最小冗余编码是指,如果知道一组数据中符号出现的频率,就可以用一种特殊的方式来表示符号从而减少数据需要的存储空间。一种方法是使用较少的位对出现频率高的符号编码,用较多的位对出现频率低的符号编码。我们要意识到,一个符号不一定必须是文本字符,它可以是任何大小的数据,但往往它只占一个字节。
熵和最小冗余
每个数据集都有一定的信息量,这就是所谓的熵 。一组数据的熵是数据中每个符号熵的总和 。符号z的熵S定义为:
Sz = -lg2 Pz
其中,Pz 就数据集中z出现的频率 。来看一个例子,如果z在有32个符号的数据集中出现了8次,也就是1/4的概率,那么z的熵就是:
-lg 2 (1/4) = 2位
这意味着如果用超过两位的数来表示z将是一种浪费。如果在一般情况下用一个字节(即8位)来表示一个符号,那么在这种情况下使用压缩算法可以大幅减小数据的容量。
下表展示如何计算一个有72个数据实例熵的例子(其中有5个不同的符号)。要做到这一点,需将每个字符的熵相加。以U为例,它在数据集中出现了12次,所以每个U的实例的熵计算如下:
符号
概率
每个实例的熵
总的熵
U
12/72
2.584 963
31.019 55
V
18/72
2.000 000
36.000 00
W
7/72
3.362 570
23.537 99
X
15/72
2.263 034
33.945 52
Y
20/72
1.847 997
36.959 94
-lg2 (12/72) = 2.584 963 位
由于U在数据中出现了12次,因此整个数据的熵为:
2.584 963 * 12 = 31.019 55 位
为了计算数据集整体的熵,将每个字符所贡献的熵相加。 每个字符的熵在表中已经计算出来了:
31.019 55 + 36.000 00 + 23.537 99 + 33.945 52 + 36.959 94 = 161.463 00 位
如果使用8位来表示每个符号,需要72 * 8 = 576位的空间,所以理论上来说,可以最多将此数据压缩:
1 - (161.463 000/576) = 72%
构造霍夫曼树
霍夫曼编码展现了一种基于熵的数据近似的最佳表现形式 。它首先生成一个称为霍夫曼树的数据结构,霍夫曼树本身是一棵二叉树,用它来生成霍夫曼编码。霍夫曼编码是用来表示数据集合中符号的编码,用这种编码的方式达到数据压缩的目的。 然而,霍夫曼编码的压缩结果往往只能接近于数据的熵,因为符号的熵往往是有小数位的,而在实际中,霍夫曼编码所用的位数不可能有小数位,所以有些代码会超过实际最优的代码位数。
下图展示了用上表中的数据来构建一棵霍夫曼树的过程。构建的过程往往是从叶子结点向上进行。首先,将每个符号和频率放到它自身的树中(步骤1) 。然后,将两个频率最小的根结点的树合并,并将其频率之和放到树的新结点中(步骤2) 。这个过程反复持续下去,直到最后只剩下一棵树(这棵树就是霍夫曼树,步骤5) 。霍夫曼的根结点包含数据中符号的总个数,它的叶子结点包含原始的符号和符号的频率 。由于霍夫曼编码就是在不断寻找两棵最适合合并的树,因此它是贪婪算法的一个很好的例子。
压缩和解压缩数据
建立一棵霍夫曼树是数据压缩和解压缩的一部分。
用霍夫曼树压缩数据,给定一个具体的符号 ,从树的根开始,然后沿着树的叶向叶子结点追踪。在向下追踪的过程中,当向左分支移动时,向当前编码的末尾追加0;当向右移动时,向当前编码的末尾追加1。 在上图中,追踪“U”的霍夫曼编码,首先向右移动(1),然后向左移动(10),然后再向右(101)。图中符号的霍夫曼编码分别为:
U=101,V=01,W=100,X=00,Y=11
要解压缩用霍夫曼树编码的数据,要一位一位地读取压缩数据。从树的根开始,当在数据中遇到0时,向树的左分支移动;当遇到1时,向右分支移动。一旦到达一个叶子结点就找到了符号。接着从头开始,重复以上过程,直到所有的压缩数据都找出。 用这种方法来解压缩数据是可能的,这是因为霍夫曼树是属于前缀树。前缀树是指一组代码中,任何一个编码都不是另一个编码的前缀。这就保证了编码被解码时不会有多义性。例如,“V”的编码是01,01不会是任何其他编码的前缀。因此,只要在压缩数据中碰到了01,就可以确定它表示的符号是“V”。
霍夫曼编码的效率
为了确定霍夫曼编码降低了多大容量的存储空间,首先要计算每个符号出现的次数与其编码位数的乘积,然后将其求和 。所以,上表中压缩后的数据的大小为:
12*3 + 18*2 + 7*3 + 15*2 +20*2 = 163位
假设不使用压缩算法的72个字符均用8位表示,那么其总共所占的数据大小为576位,所以其压缩比计算如下:
1 - (163/576)=71.7%
再次强调的是,在实际中无法用小数来表示霍夫曼编码,所以在很多情况下这个压缩比并没有数据的熵效果那么好。但也非常接近于最佳压缩比。
在通常情况下,霍夫曼编码并不是最高效的压缩方法,但它压缩和解压缩的速度非常快。一般来说,造成霍夫曼编码比较耗时的原因是它需要扫描两次数据:一次用来计算频率;另一次才是用来压缩数据。而解压缩数据非常高效,因为解码每个符号的序列只需要扫描一次霍夫曼树。
霍夫曼编码的接口定义
huffman_compress
int huffman_compress(const unsigned char *original, unsigned char **compressed, int size);
返回值 :如果数据压缩成功,返回压缩后数据的字节数;否则返回-1。
描述 :用霍夫曼编码的方法压缩缓冲区original中的数据,original包含size字节的空间。压缩后的数据存入缓冲区compressed中。由于函数调用者并不知道compressed需要多大的空间,因此需要通过函数调用malloc来动态分配存储空间。当这块存储空间不再使用时,由调用者调用函数free来释放空间。
复杂度 :O(n),其中n代表原始数据中符号的个数。
huffman_uncompress
int huffman_uncompress(const unsigned char *compressed, unsigned char **original);
返回值 :如果解压缩成功,返回恢复后数据的字节数;否则返回-1。
描述 :用霍夫曼的方法解压缩缓冲区compressed中的数据。假定缓冲区包含的数据是由Huffman_compress压缩产生的。恢复后的数据存入缓冲区original中。由于函数调用者并不知道original需要多大的空间 ,因此要通过函数调用malloc来动态分配存储空间。当这块存储空间不再使用时,由调用者调用free来释放空间。
复杂度 :O(n),其中n是原始数据中符号的个数。
霍夫曼编码的分析与实现
通过霍夫曼编码,在压缩过程中,我们将符号按照霍夫曼树进行编码从而压缩数据。在解压缩时,重建压缩过程中的霍夫曼树,同时将编码解码成符号本身。在本节介绍的实现过程中,一个原始符号都是用一个字节表示。
huffman_compress
huffman_compress操作使用霍夫曼编码来压缩数据。首先,它扫描数据,确定每个符号出现的频率。将频率存放到数组freqs中。完成对数据的扫描后,频率得到一定程度的缩放,因此它们可以只用一个字节来表示。当确定数据中某个符号的最大出现频率,并且相应确定其他频率后,这个扫描过程结束。由于数据中没有出现的符号,应该只是频率值为0的符号,所以执行一个简单的测试来确保当任何非0频率值其缩减为小于1时,最终应该将其值设为1而不是0。
一旦计算出了所有的频率,就调用函数build_tree来建立霍夫曼树。此函数首先将数据中至少出现过一次的符号插入优先队列中(实际上是一棵二叉树)。树中的结点由数据结构HuffNode定义。此结构包含两个成员:symbol为数据中的符号(仅在叶子结点中使用);freq为频率。每棵树初始状态下只包含一个结点,此结点存储一个符号和它的缩放频率(就像在数据freqs中记录和缩放的一样)。
要建立霍夫曼树,通过优先队列用一个循环对树做size-1次合并。在每次迭代过程中,两次调用pqueue_extract来提取根结点频率最小的两棵二叉树。然后,将两棵树合并到一棵新树中,将两棵树的频率和存放到新树的根结点中,接着把新的树保存回优先级队列中。这个过程会一直持续下去,直到size-1次迭代完成,此时优先级队列中只有一棵二叉树,这就是霍夫曼树。
利用上一步建立的霍夫曼树,调用函数build_table来建立一个霍夫曼编码表,此表指明每个符号的编码。表中每个条目都是一个HuffCode结构。此结构包含3个成员:used是一个默认为1的标志位,它指示此条目是否已经存放一个代码;code是存放在条目中的霍夫曼编码;size是编码包含的位数。每个编码都是一个短整数,因为可以证明当所有的频率调整到可以用一个字节来表示时,没有编码会大于16位。
使用一个有序的遍历方法来遍历霍夫曼树,从而构建这个表。在每次执行build_table的过程中,code 记录当前生成的编码,size保存编码的位数。在遍历树时,每当选择左分支时,将0追加到编码的末尾中;每当选择右分支时,将1追加到编码的末尾中。一旦到达一个叶子结点,就将霍夫曼编码存放到编码表合适的条目中。在存放每个编码的同时,调用函数htons,以确保编码是以大端字节格式存放。这一步非常重要,因为在下一步生成压缩数据时需要用大端格式,同样在解压缩过程中也需要大端格式。
在产生压缩数据的同时,使用ipos来保存原始数据中正在处理的当前字节,并用opos来保存向压缩数据缓冲区写入的当前位。首先,缩写一个头文件,这有助于在huffman_uncompress中重建霍夫曼树。这个头文件包含一个四字节的值,表示待编码的符号个数,后面跟着的是所有256个可能的符号出现的缩放频率,也包括0。最后对数据编码,一次读取一个符号,在表中查找到它的霍夫曼编码,并将每个编码存放到压缩缓冲区中。在压缩缓冲区中为每个字节分配空间。
huffman_compress的时间复杂度为O(n),其中n是原始数据中符号的数量。
huffman_uncompress
huffman_uncompress操作解压缩由huffman_compress压缩的数据。首先,此操作读取追加到压缩数据的头。回想一下,头的前4个字节包含编码符号的数量。这个值存放在size中。接下来的256个字节包含所有符号的缩放频率。
利用存放在头中的信息,调用build_tree重建压缩过程中用到的霍夫曼树。一旦重建了树,接下来就要生成已恢复数据的缓冲区。要做到这一点,从压缩数据中逐位读取数据。从霍夫曼树的根开始,只要遇到位数0,就选择左分支;只要遇到位数1,就选择右分支。一旦到达叶子结点,就获取一个符号的霍夫曼编码。解码符号存储在叶子中。所以, 将此符号写入已恢复数据的缓冲区中。写入数据之后,重新回到根部,然后重复以上过程。使用ipos来保存向压缩数据缓冲区写入的当前位,并用opos来保存写入恢复缓冲区中的当前字节。一旦opos到达size,就从原始数据中生成了所有的符号。
huffman_uncompress的时间复杂度为O(n)。其中n是原始数据中符号的数量。这是因为对每个要解码符号来说,在霍夫曼树中向下寻找的深度是一个有界常量,这个常量依赖于数据中不同符号的数量。在本节的实现中,这个常量是256.建立霍夫曼树的过程不影响huffman_uncompress的复杂度,因为这个过程只依赖于数据中不同符号的个数。
示例:霍夫曼编码的实现文件
/* huffman.c */
#include
#include in.h>
#include
#include <string .h>
#include " bit.h "
#include " bitree.h "
#include " compress.h "
#include " pqueue.h "
/* compare_freq 比较树中霍夫曼节点的频率 */
static int compare_freq(const void *tree1,const void *tree2)
{
HuffNode *root1,root2;
/* 比较两棵二叉树根结点中所存储的频率大小 */
root1 = (HuffNode *)bitree_data(bitree_root((const BiTree *)tree1));
root2 = (HuffNode *)bitree_data(bitree_root((const BiTree *)tree2));
if (root1->freq < root2->freq)
return 1 ;
else if (root1->freq > root2->freq)
return -1 ;
else return 0 ;
}
/* destroy_tree 消毁二叉树 */
static void destroy_tree(void *tree)
{
/* 从优先级队列中消毁并释放一棵二叉树 */
bitree_destroy(tree);
free (tree);
return ;
}
/* buile_tree 构建霍夫曼树,每棵树初始只包含一个根结点 */
static int bulid_tree(int *freqs,BiTree **tree)
{
BiTree *init,
*merge,
*left,
*right;
PQueue pqueue;
HuffNode *data;
int size,c;
/* 初始化二叉树优先级队列 */
*tree = NULL;
pqueue_init( &pqueue,compare_freq,destroy_tree);
for (c=0 ; c<=UCHAR_MAX; c++)
{
if (freqs[c] != 0 )
{
/* 建立当前字符及频率的二叉树 */
if ((init = (BiTree *)malloc (sizeof (BiTree))) == NULL)
{
pqueue_destroy( &pqueue);
return -1 ;
}
bitree_init(init, free );
if ((data = (HuffNode*)malloc (sizeof (HuffNode))) == NULL)
{
pqueue_destroy( &pqueue);
return -1 ;
}
data ->symbol = c;
data ->freq = freqs[c];
if (bitree_ins_left(init,NULL,data) != 0 )
{
free (data);
bitree_destroy(init);
free (init);
pqueue_destroy( &pqueue);
return -1 ;
}
/* 将二叉树插入优先队列 */
if (pqueue_insert(&pqueue,init) != 0 )
{
bitree_destroy(init);
free (init);
pqueue_destroy( &pqueue);
return -1 ;
}
}
}
/* 通过两两合并优先队列中的二叉树来构建霍夫曼树 */
for (c=1 ; c<=size-1 ; c++)
{
/* 为合并后的树分配空间 */
if ((merge = (BiTree *)malloc (sizeof (BiTree))) == NULL)
{
pqueue_destroy( &pqueue);
return -1 ;
}
/* 提取队列中拥有最小频率的两棵树 */
if (pqueue_extract(&pqueue,(void **)&left) != 0 )
{
pqueue_destroy( &pqueue);
free (merge);
return -1 ;
}
if (pqueue_extract(&pqueue,(void **)right) !=0 )
{
pqueue_destroy( &pqueue);
free (merge);
return -1 ;
}
/* 分配新产生霍夫曼结点的空间 */
if ((data = (HuffNode *)malloc (sizeof (HuffNode))) == NULL)
{
pqueue_destroy( &pqueue);
free (merge);
return -1 ;
}
memset(data, 0 ,sizeof (HuffNode));
/* 求和前面提取的两棵树的频率 */
data ->freq = ((HuffNode *)bitree_data(bitree_root(left)))->freq +
((HuffNode *)bitree_data(bitree_root(right)))->freq;
/* 合并left、right两棵树 */
if (bitree_merge(merge,left,right,data) != 0 )
{
pqueue_destroy( &pqueue);
free (merge);
return -1 ;
}
/* 把合并后的树插入到优先级队列中,并释放left、right棵树 */
if (pqueue_insert(&pqueue,merge) != 0 )
{
pqueue_destroy( &pqueue);
bitree_destroy(merge);
free (merge);
return -1 ;
}
free (left);
free (right);
}
/* 优先队列中的最后一棵树即是霍夫曼树 */
if (pqueue_extract(&pqueue,(void **)tree) != 0 )
{
pqueue_destroy( &pqueue);
return -1 ;
}
else
{
pqueue_destroy( &pqueue);
}
return 0 ;
}
/* build_table 建立霍夫曼编码表 */
static void build_table(BiTreeNode *node, unsigned short code, unsigned char size, HuffCode *table)
{
if (!bitree_is_eob(node))
{
if (!bitree_is_eob(bitree_left(node)))
{
/* 向左移动,并将0追加到当前代码中 */
build_table(bitree_left(node),code <<1 ,size+1 ,table);
}
if (!bitree_is_eob(bitree_right(node)))
{
/* 向右移动,并将1追加到当前代码中 */
build_table(bitee_right(node),(code <<1 ) | 0x0001 ,size+1 ,table);
}
if (bitree_is_eob(bitree_left(node)) && bitree_is_eob(bitree_right(node)))
{
/* 确保当前代码是大端格式 */
code = htons(code);
/* 将当前代码分配给叶子结点中的符号 */
table[((HuffNode *)bitree_data(node))->symbol].used = 1 ;
table[((HuffNode *)bitree_data(node))->symbol].code = code;
table[((HuffNode *)bitree_data(node))->symbol].size = size;
}
}
return ;
}
/* huffman_compress 霍夫曼压缩 */
int huffman_compress(const unsigned char *original, unsigned char **compressed, int size)
{
BiTree *tree;
HuffCode table[UCHAR_MAX + 1 ];
int freqs[UCHAR_MAX + 1 ],
max,
scale,
hsize,
ipos,opos,cpos,
c,i;
unsigned *comp,*temp;
/* 初始化,没有压缩数据的缓冲区 */
*compressed = NULL;
/* 获取原始数据中每个符号的频率 */
for (c=0 ; c <= UCHAR_MAX; c++)
freqs[c] = 0 ;
ipos = 0 ;
if (size > 0 )
{
while (ipos < size)
{
freqs[original[ipos]] ++;
ipos ++;
}
}
/* 将频率缩放到一个字节 */
max = UCHAR_MAX;
for (c=0 ; c<=UCHAR_MAX; c++)
{
if (freqs[c] > max)
max = freqs[c];
}
for (c=0 ; c <= UCHAR_MAX; c++)
{
scale = (int )(freqs[c] / ((double )max / (double )UCHAR_MAX));
if (scale == 0 && freqs[c] != 0 )
freqs[c] = 1 ;
else
freqs[c] = scale;
}
/* 建立霍夫曼树和编码表 */
if (build_tree(freqs,&tree) != 0 )
return -1 ;
for (c=0 ; c<=UCHAR_MAX; c++)
memset( &table[c],0 ,sizeof (HuffCode));
bulid_table(bitree_root(tree), 0x0000 , 0 , table);
bitree_destroy(tree);
free (tree);
/* 编写一个头代码 */
hsize = sizeof (int ) + (UNCHAR_MAX + 1 );
if ((comp = (unsigned char *)malloc (hsize)) == NULL)
return -1 ;
memcpy(comp, &size,sizeof (int ));
for (c=0 ; c<=UCHAR_MAX; c++)
comp[ sizeof (int ) + c] = (unsigned char )freqs[c];
/* 压缩数据 */
ipos = 0 ;
opos = hsize*8 ;
while (ipos < size)
{
/* 获取原始数据中的下一个字符 */
c = original[ipos];
/* 将字符对应的编码写入压缩数据的缓存中 */
for (i=0 ; i)
{
if (opos % 8 == 0 )
{
/* 为压缩数据的缓存区分配另一个字节 */
if ((temp = (unsigned char *)realloc (comp,(opos/8 )+1 )) == NULL)
{
free (comp);
return -1 ;
}
comp = temp;
}
cpos = (sizeof (short )*8 ) - table[c].size + i;
bit_set(comp, opos, bit_get((unsigned char *)&table[c].code,cpos));
opos ++;
}
ipos ++;
}
/* 指向压缩数据的缓冲区 */
*compressed = comp;
/* 返回压缩缓冲区中的字节数 */
return ((opos - 1 ) / 8 ) + 1 ;
}
/* huffman_uncompress 解压缩霍夫曼数据 */
int huffman_uncompress(const unsigned char *compressed, unsigned char **original)
{
BiTree *tree;
BiTreeNode *node;
int freqs[UCHAR_MAX + 1 ],
hsize,
size,
ipos,opos,
state,
c;
unsigned char *orig,*temp;
/* 初始化 */
*original = orig = NULL;
/* 从压缩数据缓冲区中获取头文件信息 */
hize = sizeof (int ) + (UCHAR_MAX + 1 );
memcpy( &size,compressed,sizeof (int ));
for (c=0 ; c<=UCHAR_MAX; c++)
freqs[c] = compressed[sizeof (int ) + c];
/* 重建前面压缩数据时的霍夫曼树 */
if (bulid_tree(freqs,&tree) != 0 )
return -1 ;
/* 解压缩数据 */
ipos = hsize * 8 ;
opos = 0 ;
node = bitree_root(tree);
while (opos < size)
{
/* 从压缩数据中获取位状态 */
state = bit_get(compressed,ipos);
ipos ++;
if (state == 0 )
{
/* 向左移动 */
if (bitree_is_eob(node) || bitree_is_eob(bitree_left(node)))
{
bitree_destroy(tree);
free (tree);
return -1 ;
}
else node = bitree_left(node);
}
else
{
/* 向右移动 */
if (bitree_is_eob(node) || bitree_is_eob(bitree_right(node)))
{
bitree_destroy(tree);
free (tree);
return -1 ;
}
else node = bitree_right(node);
}
if (bitree_is_eob(bitree_left(node)) && bitree_is_eob(bitree_right(node)))
{
/* 将叶子结点中的符号写入原始数据缓冲区 */
if (opos > 0 )
{
if ((temp = (unsigned char *)realloc (orig,opos+1 )) == NULL)
{
bitree_destroy(tree);
free (tree);
free (orig);
return -1 ;
}
orig = temp;
}
else
{
if ((orig = (unsigned char *)malloc (1 )) == NULL)
{
bitree_destroy(tree);
free (tree);
return -1 ;
}
}
orig[opos] = ((HuffNode *)bitree_data(node))->symbol;
opos ++;
/* 返回到霍夫曼树的顶部 */
node = bitree_root(tree);
}
}
bitree_destroy(tree);
free (tree);
/* 把向原始数据缓冲区 */
*original = orig;
/* 返回原始数据中的字节数 */
return opos;
}
你可能感兴趣的:(数据压缩算法---霍夫曼编码的分析与实现)
人生重开模拟器 -deepseek版
Cccc吃吃吃
python 开发语言
人生重开模拟器是一个有趣的文字类游戏,玩家可以通过选择不同的选项来体验不同的人生轨迹。下面是一个简单的Python实现,模拟了人生重开的过程。玩家可以通过输入数字来选择不同的选项,游戏会根据选择生成不同的人生结局。```pythonimportrandomdefprint_intro():print("欢迎来到人生重开模拟器!")print("你将重新开始你的人生,通过不同的选择体验不同的人生轨迹
“轻松一键生成 AI 图像:Stable Diffusion Online 带来革命性视觉创意体验!“
ai小精灵
人工智能 stable diffusion 文心一言 AI作画 chatgpt
StableDiffusionOnline正在为AI图像生成领域树立新标准,将复杂的功能与便捷直观的用户体验相结合。历史上,StableDiffusion的部署步骤带来了重大挑战,特别是对于技术新手而言。然而,StableDiffusionOnline消除了这些障碍,提供了一个既适合新手也适合资深专业人士的酷炫界面。什么是StableDiffusionOnline?StableDiffusionO
大数据最新大数据StarRocks(七):数据表创建(2)
2401_84182271
程序员 大数据
2.1表分为内部表和外部表默认未内部表,3.0版本开始集成外部数据建议使用catalog,外部表的建表方式将被弃用2.2列定义语法:col_namecol_type[agg_type][NULL|NOTNULL][DEFAULT"default\_value"][AUTO_INCREMENT][ASgeneration_expr]col_name:列名称注意,在一般情况下,不能直接创建以以__op
算法入门——二分法
Able Zhao 650829
算法 数据结构 c++ 蓝桥杯
二分法真的很容易出错!!!在用dp学习之后总结了一下二分法二分查找关键总结一、核心思想分治策略:每次将搜索范围缩小一半,适用于有序数组。时间复杂度:O(logn),比线性查找高效得多。二、关键点前提条件有序性:数组必须有序(升序或降序),否则需先排序(但排序成本O(nlogn))。静态性:适合静态数据或低频更新的数据(高频更新建议用哈希表或树结构)。两种边界问题左边界:第一个等于目标的位置(或第一
PTA天梯赛Python7-52 古风排版
胡同Alley
python
中国的古人写文字,是从右向左竖向排版的。本题就请你编写程序,把一段文字按古风排版。输入格式:输入在第一行给出一个正整数N(<100),是每一列的字符数。第二行给出一个长度不超过1000的非空字符串,以回车结束。输出格式:按古风格式排版给定的字符串,每列N个字符(除了最后一列可能不足N个)。输入样例:4Thisisatestcase输出样例:asaTstihetsices代码长度限制16KB时间限制
STM32HAL库,解决串口UART中断接收到的第一个字节数据丢失
IT.小航
STM32-—hal库 stm32 单片机 嵌入式硬件
1.问题描述:只有上电后第一次接收到的第一字节数据会丢失,往后再接收也不会存在问题了。2.先贴出来重写UART中断回调函数我在接收到第一字节数据后开启定时器中断的,做一个超时处理,每次接收到数据会对定时器计数值清零,如果超过6ms则认为一帧数据接收完毕。voidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart){if(huart->Instance=
详细介绍 Jupyter nbconvert 工具及其用法:如何将 Notebook 转换为 Python 脚本
源代码杀手
python使用技巧 python jupyter ide
nbconvert是Jupyter提供的一个非常强大的工具,允许用户将JupyterNotebook文件(.ipynb)转换成多种格式,包括Python脚本(.py)、HTML、PDF、LaTeX等。你可以通过命令行来运行nbconvert,也可以在JupyterNotebook中通过一些自定义的设置来实现转换。安装nbconvert通常情况下,nbconvert会随Jupyter一起安装,因此不
系统架构设计(以飞控系统、航电系统、机电管理系统、电子电气架构为例)
机载软件与适航
机载系统 系统工程 适航 系统架构 架构
架构的定义系统架构涉及对系统的结构和行为进行高层次的描述。它包括系统的组成部分、这些部分之间的关系、与外部环境的交互方式,以及满足特定功能和非功能性需求的方法。系统架构定义了系统的总体设计蓝图,指导系统的开发、集成、部署和维护。系统架构的核心要素组成部分(Components):系统中的独立模块或单元,每个模块执行特定的功能。组件可以是软件模块、硬件设备、数据库、用户界面等。组件间的关系(Rela
Starrocks 命令 Alter table DISTRIBUTED 重分布数据的实现
鸿乃江边鸟
大数据 StarRocks starrocks 大数据
背景在前文Starrocks写入报错primarykeymemoryusageexceedsthelimit中,可以通过ALTERTABLExxxxDISTRIBUTEDBYHASH(xx)BUCKETS50;来改变数据的分布状态,具体的执行过程是怎么样的呢?分析首先对应的g4文件中为alterTableStatement,这里最终的调用是AlterJobExecutor.visitAlterTa
python -- assert函数
我不是程序员
python知识 python
一、assert函数在Python中,assert语句用于调试和测试代码。它用于检查某个条件是否为真。如果条件为假,assert语句会抛出一个AssertionError异常,并可以选择性地附加一条错误消息。assert语句的基本语法是:assertcondition,optional_messagecondition:一个布尔表达式。如果结果为True,程序继续执行。如果为False,会触发As
Beekeeper Studio:高颜值且免费的SQL开发工具
开源项目精选
sql 数据库
BeekeeperStudio是一款免费开源的SQL开发和数据库管理工具,具有美观高效、简单易用的特点。BeekeeperStudio基于Vue.js开发,遵循MIT开源协议,支持Windows、Linux以及macOS平台。Stars数17842Forks数1170主要特点安全连接:除了正常的连接,也可以使用SSL加密连接或通过SSH隧道连接;SQL自动补全:代码编辑器支持语法高亮和表名自动补全
kvm虚拟化的概念与作用
千航@abc
kvm虚拟化 kvm 虚拟化
概念——虚拟化是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机。在一台计算机上同时运行多个逻辑计算机,每个逻辑计算机可运行不同的操作系统,并且应用程序都可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率。作用——虚拟化技术可以扩大硬件的容量,简化软件的重新配置过程。CPU的虚拟化技术可以单CPU模拟多CPU并行,允许一个平台同时运行多个操作系统,并且应用程序都可以在相互独立的空间
PCDN如何优化移动设备的网络体验
yczykjyxgs
pcdn 服务器
在移动互联网时代,用户对网络体验的要求不断提升,PCDN(P2PCDN)技术为优化移动设备网络体验提供了创新解决方案。这项技术通过重构传统内容分发模式,有效解决了移动网络环境下的带宽瓶颈和传输延迟问题。PCDN技术的核心在于构建了一个去中心化的内容分发网络。移动设备不再仅仅作为内容消费者,而是同时承担了内容分发节点的角色。这种设计充分利用了移动设备的闲置带宽和存储资源,形成了一个动态的内容共享网络
## PCDN中的网络拥塞控制技术探讨
yczykjyxgs
pcdn 网络 智能路由器
随着互联网视频流量的爆发式增长,传统CDN面临着成本高、扩展性差等挑战。P2PCDN(PCDN)作为一种新兴的内容分发网络架构,通过利用边缘节点的闲置带宽和存储资源,有效降低了内容分发成本,并提升了网络扩展性。然而,PCDN中节点动态性强、网络环境复杂,传统的网络拥塞控制技术难以直接适用,因此需要针对PCDN的特点设计新的拥塞控制机制。PCDN网络拥塞控制面临的挑战1.节点异构性:PCDN节点性能
PCDN 与传统 CDN 的对比:优势和劣势分析
yczykjyxgs
pcdn 智能路由器
在内容分发领域,PCDN和传统CDN是两种重要的技术手段。传统CDN凭借其成熟的架构,在互联网发展历程中发挥着关键作用。它通过在各地广泛部署缓存服务器,将内容缓存至离用户更近的节点,以此加快分发速度。这种模式下,内容传输路径短,能有效减少延迟,为用户提供稳定的访问体验。不过,传统CDN的大规模服务器部署带来了高昂成本,无论是建设费用还是维护成本都不容小觑。PCDN作为融合了P2P技术的新兴内容分发
我所认识的区块链
whg1016
区块链
什么是区块链区块链是一个多节点共同参与,共同确认的记账系统,账本由是由一串串数据块组成的,下一个数据块记录了上个数据的hash,所有的块按照顺序形成一个完整的数据链条。每个节点都有完全一致的账本数据,记录的数据不可篡改和不可伪造。这个链条被保存在所有的服务器中,只要整个系统中有一台服务器可以工作,整条区块链就是安全的。区块链的由来区块链起源于Bitcoin,2008年11月1日,一位自称中本聪(S
鸿蒙HarmonyOS实战:应用程序包-HAP
让开,我要吃人了
harmonyos 华为
HAP(HarmonyAbilityPackage)是应用安装和运行的基本单元。HAP包是由代码、资源、第三方库、配置文件等打包生成的模块包,其主要分为两种类型:entry和feature。entry:应用的主模块,作为应用的入口,提供了应用的基础功能。feature:应用的动态特性模块,作为应用能力的扩展,可以根据用户的需求和设备类型进行选择性安装。应用程序包可以只包含一个基础的entry包,也
鸿蒙HarmonyOS开发:应用程序静态包-HAR
让开,我要吃人了
鸿蒙开发 OpenHarmony HarmonyOS harmonyos 华为 移动开发 前端 html 开发语言 鸿蒙
HAR(HarmonyArchive)是静态共享包,可以包含代码、C++库、资源和配置文件。通过HAR可以实现多个模块或多个工程共享ArkUI组件、资源等相关代码。使用场景作为二方库,发布到OHPM私仓,供公司内部其他应用使用。作为三方库,发布到OHPM中心仓,供其他应用使用。约束限制HAR不支持在设备上单独安装/运行,只能作为应用模块的依赖项被引用。HAR不支持在配置文件中声明UIAbility
CTF杂项挑战:使用已知字典破解ZIP文件密码
0dayNu1L
Web安全 CTF web安全 网络安全
在CTF比赛中,杂项挑战通常包含一些非传统的题目,其中破解ZIP文件密码是一个常见的任务。本文将介绍两种在已知密码字典文件的情况下,破解ZIP文件密码的方法:一种是使用Python脚本进行暴力破解,另一种是通过zip2john和john命令结合进行破解。0dayNu1L-CSDN博客请一键三连吧!!!❤❤❤目录方法一:使用Python脚本进行暴力破解步骤方法二:使用zip2john和john命令结
文本转语音的Python库(pyttsx3)
数产第一混子
python库 python
一、pyttsx3的概述pyttsx3isatext-to-speechconversionlibraryinPython.pyttsx3是Python中的文本到语音转换库。二、pyttsx3的安装pipinstallpyttsx3三、小试牛刀importpyttsx3engine=pyttsx3.init()engine.say("Iwillspeakthistextrightnow")engi
近期计算机领域的热点技术
0dayNu1L
云计算 量子计算 人工智能
随着科技的飞速发展,计算机领域的新技术、新趋势层出不穷。本文将探讨近期计算机领域的几个热点技术趋势,并对它们进行简要的分析和展望。一、人工智能与机器学习人工智能(AI)和机器学习(ML)是近年来计算机领域最为热门的话题之一。AI和ML技术已经广泛应用于图像识别、自然语言处理、智能推荐等领域,并取得了显著的成果。随着技术的不断进步,AI和ML将更深入地渗透到各个行业,为人类社会带来更多便利和效益。在
区块链赋能:用Python开发去中心化投票系统
Echo_Wish
Python! 实战! 区块链 python 去中心化
区块链赋能:用Python开发去中心化投票系统在这个互联网迅猛发展的时代,投票系统不仅仅停留在政务领域,它已成为社区治理、企业决策甚至区块链DAO(去中心化自治组织)中重要的机制。然而,传统投票系统往往集中化,存在信任和数据安全问题。区块链技术以其不可篡改性和透明性为去中心化投票提供了理想的解决方案。在这篇文章中,我将通过Python语言,结合区块链智能合约,教你如何从零开发一个去中心化的投票系统
Python助力区块链互通——跨链桥接的实现与实践
Echo_Wish
Python! 实战! 区块链 python 开发语言
Python助力区块链互通——跨链桥接的实现与实践区块链技术的繁荣发展带来了巨大的生态创新,但也因各链之间的割裂局面限制了它们的潜力。例如,你或许想在以太坊上使用来自比特币的资产,却因两条链不互通而不得不求助于中心化交易所。要打破“链间壁垒”,跨链桥接(Cross-chainBridge)应运而生。今天,我以Echo_Wish的视角,通过Python代码实践,带你深入了解跨链桥接的工作原理,技术实
Peach-Editor,一款Web版电子病例编辑器实验版本上线了
大神1573
Peach-Editor 编辑器
经过一年多的辛苦钻研,一款web版本的电子病例编辑器基础word编辑功能版本终于和大家见面了,编辑器实现了参照传统文档编辑习惯,尽可能的还原原汁原味的文档编辑体验。目前初步完成了基础的文本编辑、表格、分页、页面控制等后续还加加入电子病例相关内容,整个编辑器的研发进度正在有序推进中,现将阶段性成果展示给大家。整体界面,沿用了传统的文档编辑习惯,菜单栏分为文件、编辑、插入、页面、审阅。编辑菜单内容主要
Parrot OS 6.3 发布!全面提升安全性,新增先进工具,带来更高性能
wljslmz
Linux技术 linux Parrot OS
2025年2月,全球知名的安全和隐私为核心的Linux发行版——ParrotOS迎来了其最新版本——ParrotOS6.3。作为一款基于Debian的多功能操作系统,ParrotOS旨在为安全专家、开发人员以及关注隐私的用户提供强大的功能支持。ParrotOS6.3版本在性能、工具更新、硬件支持等方面进行了一系列优化,凭借其更加稳定的安全性,最新的工具包,以及对硬件兼容性的大幅提升,ParrotO
oracle当前耗时sql语句,查看Oracle最耗时的SQL
weixin_39846553
oracle当前耗时sql语句
有很多种方法可以用来找出哪些sql语句需要优化,但是很久以来,最简单的方法都是分析保存在V$sql视图中的缓存的sql信息。通过V$sql视图,可以确定具有高消耗时间、CUP和IO读取的sql语句。1.查看总消耗时间最多的前10条sql语句select*from(selectv.sql_id,v.child_number,v.sql_text,last_load_time,v.PARSING_US
DevOps中集成自动化测试的具体案例
Zachary AI
CICD相关 devops 运维
在DevOps中集成自动化测试的具体案例可以从多个角度进行分析,包括金融行业、分布式系统、大型企业等不同领域的实践。以下是几个具体的案例:金融行业的DevOps实践:在金融行业中,DevOps被广泛应用于提升软件开发和运营的效率。例如,通过解析后台接口代码日志格式,自动化生成接口测试案例,解决了接口自动化测试过程中各交易输入值难以确定的问题,从而提高了接口测试效率[14]。此外,农行手机银行系统存
技术沙龙 | 从高并发架构到企业级区块链探索零售创新
weixin_33984032
区块链 python 数据库
2019独角兽企业重金招聘Python工程师标准>>>伴随消费新理念的不断升级和技术创新发展,零售业逐渐被推到风口浪尖,对此京东曾表示,推动“无界零售”时代的到来理念,倡导实现成本、效率、体验的升级才是终极目标。此概念一出,零售行业的侧重点开始由销售端向技术端倾斜,趁着一年一度618来临之际,京东云特别在上海举办了主题为"从高并发架构到企业级区块链,探索无界零售的数字化创新"的技术沙龙活动。本次活
【Spring AI】基于专属知识库的RAG智能问答小程序开发——代码逐行精讲:核心交互函数及RAG知识库构建
un_fired
spring 人工智能 java
系列文章目录【SpringAI】基于专属知识库的RAG智能问答小程序开发——完整项目(含完整前端+后端代码)【SpringAI】基于专属知识库的RAG智能问答小程序开发——代码逐行精讲:核心ChatClient对象相关构造函数【SpringAI】基于专属知识库的RAG智能问答小程序开发——代码逐行精讲:核心交互函数及RAG知识库构建文章目录系列文章目录前言1.Service层知识库构建与检索函数详
关于STM32如何选择:HAL与标准库的抉择及初学者建议
笑靥藏情.
stm32 嵌入式硬件 单片机
STM32是意法半导体(STMicroelectronics)推出的一系列基于ARMCortex-M内核的32位微控制器,因其高性能、多功能性和成本效益而广受嵌入式系统开发者的欢迎。对于初学者而言,学习STM32编程时面临的第一个重要抉择往往是如何选择编程方式:是使用硬件抽象层(HAL),还是选择标准外设库(StandardPeripheralLibrary)?本文将围绕这一问题展开,详细比较HA
分享100个最新免费的高匿HTTP代理IP
mcj8089
代理IP 代理服务器 匿名代理 免费代理IP 最新代理IP
推荐两个代理IP网站:
1. 全网代理IP:http://proxy.goubanjia.com/
2. 敲代码免费IP:http://ip.qiaodm.com/
120.198.243.130:80,中国/广东省
58.251.78.71:8088,中国/广东省
183.207.228.22:83,中国/
mysql高级特性之数据分区
annan211
java 数据结构 mongodb 分区 mysql
mysql高级特性
1 以存储引擎的角度分析,分区表和物理表没有区别。是按照一定的规则将数据分别存储的逻辑设计。器底层是由多个物理字表组成。
2 分区的原理
分区表由多个相关的底层表实现,这些底层表也是由句柄对象表示,所以我们可以直接访问各个分区。存储引擎管理分区的各个底层
表和管理普通表一样(所有底层表都必须使用相同的存储引擎),分区表的索引只是
JS采用正则表达式简单获取URL地址栏参数
chiangfai
js 地址栏参数获取
GetUrlParam:function GetUrlParam(param){
var reg = new RegExp("(^|&)"+ param +"=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if(r!=null
怎样将数据表拷贝到powerdesigner (本地数据库表)
Array_06
powerDesigner
==================================================
1、打开PowerDesigner12,在菜单中按照如下方式进行操作
file->Reverse Engineer->DataBase
点击后,弹出 New Physical Data Model 的对话框
2、在General选项卡中
Model name:模板名字,自
logbackのhelloworld
飞翔的马甲
日志 logback
一、概述
1.日志是啥?
当我是个逗比的时候我是这么理解的:log.debug()代替了system.out.print();
当我项目工作时,以为是一堆得.log文件。
这两天项目发布新版本,比较轻松,决定好好地研究下日志以及logback。
传送门1:日志的作用与方法:
http://www.infoq.com/cn/articles/why-and-how-log
上面的作
新浪微博爬虫模拟登陆
随意而生
新浪微博
转载自:http://hi.baidu.com/erliang20088/item/251db4b040b8ce58ba0e1235
近来由于毕设需要,重新修改了新浪微博爬虫废了不少劲,希望下边的总结能够帮助后来的同学们。
现行版的模拟登陆与以前相比,最大的改动在于cookie获取时候的模拟url的请求
synchronized
香水浓
java thread
Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍然
maven 简单实用教程
AdyZhang
maven
1. Maven介绍 1.1. 简介 java编写的用于构建系统的自动化工具。目前版本是2.0.9,注意maven2和maven1有很大区别,阅读第三方文档时需要区分版本。 1.2. Maven资源 见官方网站;The 5 minute test,官方简易入门文档;Getting Started Tutorial,官方入门文档;Build Coo
Android 通过 intent传值获得null
aijuans
android
我在通过intent 获得传递兑现过的时候报错,空指针,我是getMap方法进行传值,代码如下 1 2 3 4 5 6 7 8 9
public
void
getMap(View view){
Intent i =
apache 做代理 报如下错误:The proxy server received an invalid response from an upstream
baalwolf
response
网站配置是apache+tomcat,tomcat没有报错,apache报错是:
The proxy server received an invalid response from an upstream server. The proxy server could not handle the request GET /. Reason: Error reading fr
Tomcat6 内存和线程配置
BigBird2012
tomcat6
1、修改启动时内存参数、并指定JVM时区 (在windows server 2008 下时间少了8个小时)
在Tomcat上运行j2ee项目代码时,经常会出现内存溢出的情况,解决办法是在系统参数中增加系统参数:
window下, 在catalina.bat最前面
set JAVA_OPTS=-XX:PermSize=64M -XX:MaxPermSize=128m -Xms5
Karam与TDD
bijian1013
Karam TDD
一.TDD
测试驱动开发(Test-Driven Development,TDD)是一种敏捷(AGILE)开发方法论,它把开发流程倒转了过来,在进行代码实现之前,首先保证编写测试用例,从而用测试来驱动开发(而不是把测试作为一项验证工具来使用)。
TDD的原则很简单:
a.只有当某个
[Zookeeper学习笔记之七]Zookeeper源代码分析之Zookeeper.States
bit1129
zookeeper
public enum States {
CONNECTING, //Zookeeper服务器不可用,客户端处于尝试链接状态
ASSOCIATING, //???
CONNECTED, //链接建立,可以与Zookeeper服务器正常通信
CONNECTEDREADONLY, //处于只读状态的链接状态,只读模式可以在
【Scala十四】Scala核心八:闭包
bit1129
scala
Free variable A free variable of an expression is a variable that’s used inside the expression but not defined inside the expression. For instance, in the function literal expression (x: Int) => (x
android发送json并解析返回json
ronin47
android
package com.http.test;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import
一份IT实习生的总结
brotherlamp
PHP php资料 php教程 php培训 php视频
今天突然发现在不知不觉中自己已经实习了 3 个月了,现在可能不算是真正意义上的实习吧,因为现在自己才大三,在这边撸代码的同时还要考虑到学校的功课跟期末考试。让我震惊的是,我完全想不到在这 3 个月里我到底学到了什么,这是一件多么悲催的事情啊。同时我对我应该 get 到什么新技能也很迷茫。所以今晚还是总结下把,让自己在接下来的实习生活有更加明确的方向。最后感谢工作室给我们几个人这个机会让我们提前出来
据说是2012年10月人人网校招的一道笔试题-给出一个重物重量为X,另外提供的小砝码重量分别为1,3,9。。。3^N。 将重物放到天平左侧,问在两边如何添加砝码
bylijinnan
java
public class ScalesBalance {
/**
* 题目:
* 给出一个重物重量为X,另外提供的小砝码重量分别为1,3,9。。。3^N。 (假设N无限大,但一种重量的砝码只有一个)
* 将重物放到天平左侧,问在两边如何添加砝码使两边平衡
*
* 分析:
* 三进制
* 我们约定括号表示里面的数是三进制,例如 47=(1202
dom4j最常用最简单的方法
chiangfai
dom4j
要使用dom4j读写XML文档,需要先下载dom4j包,dom4j官方网站在 http://www.dom4j.org/目前最新dom4j包下载地址:http://nchc.dl.sourceforge.net/sourceforge/dom4j/dom4j-1.6.1.zip
解开后有两个包,仅操作XML文档的话把dom4j-1.6.1.jar加入工程就可以了,如果需要使用XPath的话还需要
简单HBase笔记
chenchao051
hbase
一、Client-side write buffer 客户端缓存请求 描述:可以缓存客户端的请求,以此来减少RPC的次数,但是缓存只是被存在一个ArrayList中,所以多线程访问时不安全的。 可以使用getWriteBuffer()方法来取得客户端缓存中的数据。 默认关闭。 二、Scan的Caching 描述: next( )方法请求一行就要使用一次RPC,即使
mysqldump导出时出现when doing LOCK TABLES
daizj
mysql mysqdump 导数据
执行 mysqldump -uxxx -pxxx -hxxx -Pxxxx database tablename > tablename.sql
导出表时,会报
mysqldump: Got error: 1044: Access denied for user 'xxx'@'xxx' to database 'xxx' when doing LOCK TABLES
解决
CSS渲染原理
dcj3sjt126com
Web
从事Web前端开发的人都与CSS打交道很多,有的人也许不知道css是怎么去工作的,写出来的css浏览器是怎么样去解析的呢?当这个成为我们提高css水平的一个瓶颈时,是否应该多了解一下呢?
一、浏览器的发展与CSS
《阿甘正传》台词
dcj3sjt126com
Part Ⅰ:
《阿甘正传》Forrest Gump经典中英文对白
Forrest: Hello! My names Forrest. Forrest Gump. You wanna Chocolate? I could eat about a million and a half othese. My momma always said life was like a box ochocol
Java处理JSON
dyy_gusi
json
Json在数据传输中很好用,原因是JSON 比 XML 更小、更快,更易解析。
在Java程序中,如何使用处理JSON,现在有很多工具可以处理,比较流行常用的是google的gson和alibaba的fastjson,具体使用如下:
1、读取json然后处理
class ReadJSON
{
public static void main(String[] args)
win7下nginx和php的配置
geeksun
nginx
1. 安装包准备
nginx : 从nginx.org下载nginx-1.8.0.zip
php: 从php.net下载php-5.6.10-Win32-VC11-x64.zip, php是免安装文件。
RunHiddenConsole: 用于隐藏命令行窗口
2. 配置
# java用8080端口做应用服务器,nginx反向代理到这个端口即可
p
基于2.8版本redis配置文件中文解释
hongtoushizi
redis
转载自: http://wangwei007.blog.51cto.com/68019/1548167
在Redis中直接启动redis-server服务时, 采用的是默认的配置文件。采用redis-server xxx.conf 这样的方式可以按照指定的配置文件来运行Redis服务。下面是Redis2.8.9的配置文
第五章 常用Lua开发库3-模板渲染
jinnianshilongnian
nginx lua
动态web网页开发是Web开发中一个常见的场景,比如像京东商品详情页,其页面逻辑是非常复杂的,需要使用模板技术来实现。而Lua中也有许多模板引擎,如目前我在使用的lua-resty-template,可以渲染很复杂的页面,借助LuaJIT其性能也是可以接受的。
如果学习过JavaEE中的servlet和JSP的话,应该知道JSP模板最终会被翻译成Servlet来执行;而lua-r
JZSearch大数据搜索引擎
颠覆者
JavaScript
系统简介:
大数据的特点有四个层面:第一,数据体量巨大。从TB级别,跃升到PB级别;第二,数据类型繁多。网络日志、视频、图片、地理位置信息等等。第三,价值密度低。以视频为例,连续不间断监控过程中,可能有用的数据仅仅有一两秒。第四,处理速度快。最后这一点也是和传统的数据挖掘技术有着本质的不同。业界将其归纳为4个“V”——Volume,Variety,Value,Velocity。大数据搜索引
10招让你成为杰出的Java程序员
pda158
java 编程 框架
如果你是一个热衷于技术的
Java 程序员, 那么下面的 10 个要点可以让你在众多 Java 开发人员中脱颖而出。
1. 拥有扎实的基础和深刻理解 OO 原则 对于 Java 程序员,深刻理解 Object Oriented Programming(面向对象编程)这一概念是必须的。没有 OOPS 的坚实基础,就领会不了像 Java 这些面向对象编程语言
tomcat之oracle连接池配置
小网客
oracle
tomcat版本7.0
配置oracle连接池方式:
修改tomcat的server.xml配置文件:
<GlobalNamingResources>
<Resource name="utermdatasource" auth="Container"
type="javax.sql.DataSou
Oracle 分页算法汇总
vipbooks
oracle sql 算法 .net
这是我找到的一些关于Oracle分页的算法,大家那里还有没有其他好的算法没?我们大家一起分享一下!
-- Oracle 分页算法一
select * from (
select page.*,rownum rn from (select * from help) page
-- 20 = (currentPag