位图应用: 非负数排序、去重等
实现:(利用 unsigned 数组: 考虑下为什么(提示:count))
假定一个正整数 n, 其所在位置为: int 数组 A[] 中第 n / 32 个整数中的第 n % 32 个 bit 处。
n / 32 <==> n >> 5
n % 32 <==> n & ox1f (或 31)。(注意: mod (2, 4, 8, 16, 32, 64, 128, 256, 512, ...) <==> & (1, 3, 7, 15, 31, 63, 127, 255, 511, ...))
举例实现:1. 字符串去重 && 排序
#include <stdio.h> unsigned A[8]; // 256 bit char s[] = "4f3 ghl1ta;3gs4-s-s1j_av2bjl;j''faj;g2a3i4"; void set (char c) { A[c >> 5] |= (1 << (c & 31)); } unsigned check (char c) { return A[c >> 5] & (1 << (c & 31)); } int main() { int i = -1, sz = 0; while(s[++i]) if(!check(s[i])) { s[sz++] = s[i]; set(s[i]);} s[sz] = 0; puts(s); i = 0, sz = 0; for(i = 0; i < 256; ++i) if (check(i)) s[sz++] = i; puts(s); return 0; }
2. 数组中每个数最多保留 8 个。并排序。
选取 4 个 bits 来统计一个数。 最后计数排序。
#include <stdio.h> #define UNIT ((v) >> 3 ) #define POS (((v) & 7) << 2) // 4 * (v % 8), in UNIT v / 8. unsigned A[128]; // 128 * 8 bits > 4 * 255 bits char s[] = "777777777777777777777fffffffffffffffffffffffffffff11116666"; void add (char v) { A[UNIT] += (1 << POS); } void reduce(char v) { A[UNIT] -= (1 << POS); } unsigned count (char v) { return (A[UNIT] & (15 << POS)) >> POS; } void clear(char v) { A[UNIT] &= ~(0xf << POS); } int main() { int i = -1, sz = 0; puts(s); while(s[++i]) if (count(s[i]) < 8) { add(s[i]); s[sz++] = s[i]; } // 去掉超出的数 s[sz] = 0; puts(s); sz = 0; for(i = 0; i < 256; ++i) { while (count(i) > 0) { s[sz++] = i; reduce(i); } // 计数排序 } puts(s); return 0; }