散列 桶排序 最大间隙 基数排序 bitmap by邓俊辉老师

散列 (哈希)

实现一种快速索引

call by value 通过值去索引。
java 中有 HashMap散列 和 Hashtable散列表 利用key-value pair存到相应的位置。
python 中有 dictionary字典 利用hashtable

数据结构和算法是硬币的两面。hashtable是一种数据结构,而hash是一种算法。

在字符串匹配的BC表中 bad character 如果是unicode那么BC表存储的大小为65536。存在数据存储的问题???
1、space 空间大小,效率(利用率)。
2、time 需要做一个初始化。for… 或者 memset…

哈希算法:

如果开一个非常大列表,所有的查询操作仅需要O(1)的时间。但是需要的空间非常大、利用率非常低。
基于该朴素的思想,假象开一个这么大的空间,但是之前的一一对应之间加入一个hashtable。
一共分为两步:keys——hashtable——entry 此时散列表可以做得更小。

假设中间的hashtable的值为90001(素数) hash(key) = key%M 但是会存在冲突的情况。key不同但hash值相同。
如果不存在冲突的情况就是完美散列。perfect hashing。 Synonym collision 同义冲突 将出现collision情况的key称为synonym同义词。

hash函数有以下几种:
1、Division-Remainder 取模函数(mod) :存在零点不动点。邻近数依然相邻。
2、Mulitiply-Add-Division(MAD): (a*key+b)%M 改进了上面两点
3、Selecting Digits 选择数位法 奇偶错位法
4、Mid-Square 混沌 平方去中间三位值

多项式polynomial散列码的移位实现:
hashcode()函数将不是整数的数据(如字符串)进行预处理转换为整数。

static size_t hashCode( char s[] ){
	unsigned int h = 0;
	for( size_t  n=strlen(s), i=0; i<n; i++ )
		{ h = (h<<5) | (h>>27) ;  h += ( int ) s[i] ; } //散列码循环左移五位再累加当前字符。
	return (size_t) h; 
} //循环移位5个 是根据经验的得到的

利用多项式散列码可以避免类似于tops和stop之类的冲突。

如果真的发生collision冲突,该如何解决呢 。散列表hashtable=bucketarray
bucket array 每个桶都存了一个索引。
在期望意义下,其复杂度为O(1).

open-hashing — close-addressing 利用率由于link的存在,因此也利用率不超过50%。 查询时有一个key-hash()-entry。
open指散列表在某个地方还可以利用list再延长。也就是独立链法
定址close指任何一个地址,要么是空的,要么就是存储它所指向的值。

close-hashing — open-addressing
close是指计算出hash位置后,不会像open一样,生成link,而是另找隔壁或者找差分数组后的位置,步长发生变化。1、3、5、7… 差分的数组。后者也称之为平方试探(quadratic probing)。
open是指地址不是固定。

Bucketsort 桶排序

m个桶,n个数
初始化initialO(m)—分配distrO(n)—collection收集O(m)。 当n远大于m时,该算法比较好。会变成一个线性的排序算法。
stability + deduplicate 算法的稳定性。同一组的同义词。在最终输出的有序序列中,要保持原有的有序性,2a始终在2b&2c之前。是否能够一直保持这种性质。如何做的分配,如何收集起来——以保持算法的稳定性呢。

Max - Gap 最大间隙

求一段序列切分过以后,最长的序列。
Navie 算法(brute force): sorting + scan lo—hi 记录d 最少需要O(nlogn) 并不认为是一个好的解法希望做到O(n).
改进:花线性的时间寻找到lo&hi。等间距寻找,n-1个桶,最后在配上一个桶单独罩住hi。[lo,hi)
仿照bucketsort 对每个切分点做一个分配。有些桶里会有点落进去,删除非空桶。对于每一个非空的桶。只记其中最左边和最右边的点,落于中间的切点可以忽略不计。遍历,前后非空桶之间会有空的gap。寻找出maxgap。
原理:n-1个间隙的maxgap不会低于平均宽度(lo-hi/n-1) 最宽的一定比平均值大。也就是4个O(n)。
巧妙利用了分桶的策略,降低复杂度。

radixsort 基数排序 : lexicographioc order 字典序

radix 基数
逐列(位):桶排序。先对个位数进行桶排列。bucketsort。十进制准备十个桶就够了
correctness & Stability 稳定性,因为先对低位进行过排序,再对高位进行排序。因此,高位相同时,低位的大小影响其大小比较。
从低位开始逐一做一个bucketsort。 也为O(n)

Bitmap:Structure 数据结构

位图 长度。(以char为单位 也就是一个字节八位)
如何存储整数的子集。相当于一个映射表,只要记录1和0就可以了。

class Bitmap{
private:
	int N;	//位图长度(以sizeof(char)为单位)
	 char * M; //以char(8比特)为单位的比特位图
public:
	Bitmap( int n=8 ) { M = new char[N  = (n+7)/8 ]; memset(M, 0, N ); }
	~Bitmap() { delete [] M; M = NULL; } //析构
	void set( int k ); void clear( int k ); bool test( int k ); //ADT  
}

union() clear() test() 对集合中的元素进行操作。变成位图进行实现。

void set( int k )
	{ expand( k ); M[ k>>3 ] |= (0x80 >> (k & 0x07) ); }
void clear( int k )
	{ expand( k ); M[ k>>3 ] &= ~(0x80 >> (k & 0x07) ); }
void test( int k )
	{ expand( k ); return M[k >> 3] & (0x80 >> (k&0x07) ); }

k/8 就是k>>3 k右移三位。右移操作比除法要快。挪到相应的字节位置。
k%8 就是 k & 0x07 按位与。 0x80 — 1000 0000 代表8位 后移几位由k&0x07确定。 0x80 >> (k&0x07) 会得到一个mask,来测试该位是否为1。
基本功是test 由test可以得到 clear 和 set 操作。

bitmap应用 Eratosthenes:Idea 素数的筛法
void Eratosthenes( int n, char * file ){
	Bitmap B(n);
	B.set(0); B.set(1);
	for(int i=2; i<n; i++)
		if( !B.test(i) ) //断定i是素数prime
			for(int j=2*i; j<n; j+=i)
				B.set(j);
	B.dump(file);
}
散列表的缺陷。初始化需要O(n)时间

在这里插入图片描述Hopcroft 发明的O(1)时间初始化。
代价是需要除B[]外的两倍空间。 F[]&T[]。
F暗示from ;T暗示to
校验环:凡是出现校验环的位置是有效的位置,没有的话就不是有效位置。F[ T[x] ] = x
还有一个top值,只有在top值的左边才是有效的。top值所指的位置不是有效。

clear:删除元素的操作
末尾易操作。
中间元素的操作:把栈尾元素需要挪到待删除元素 。 top–。需要同时修改F中相应数组的元素。

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页