上次介绍了哈希的开闭散列,其实它还有位图以及布隆过滤器。
1.位图:
它还是分类,十分适合处理大数据量的问题。它是将数组分为好几块,每一块是所求数据类型的比特位大小。通过看比特位上是否为1,知道它是否存在。以下是它的基本用法:
#pragma once
#include
#include
#include
#include
typedef unsigned int uint32_t;
typedef struct BitArraay{ //哈希位图结构。
uint32_t *array;
unsigned int capacity;
unsigned int size;
}BitArray;
void BAInit(BitArray *pBA,unsigned int size) //初始化
{
unsigned int capacity=size/32; //算出位图的容量,这里采取了向上取整。
if(size%sizeof(uint32_t)!=0)
{
capacity+=1;
}
pBA->capacity=capacity;
pBA->size=size;
pBA->array=(uint32_t*)calloc(sizeof(uint32_t),capacity); //开辟数组空间并赋0.
}
void BitArrayDestroy(BitArray *pBA) //销毁
{
free(pBA->array); //直接释放数组。
}
void Set0(BitArray *pBA,unsigned int n) //将指定位设为0.
{
unsigned int a=n/32; //算出数的指定位置。
unsigned int b=n % 32;
pBA->array[a] &=(~(1 << b )); //用按位与让指定位变成0,其它位不变。
}
void Set1(BitArray *pBA,unsigned int n) //将指定位设为1.
{
unsigned int a=n/32;
unsigned int b=n%32;
pBA->array[a]=pBA->array[a] | (1 << b); //先对1左移后取反,再让其与该位置按位或即可。
}
int Find(BitArray *pBA,unsigned int n) //查找
{
unsigned int a=n/32;
unsigned int b=n % 32;
return (pBA->array[a] & 1 << b) >> b; //将该位置按位与上左移后的1,在右移回去,若是1即存在,否则不存在。
}
void test4()
{
int i;
BitArray p;
unsigned int array[] = {
3, 5, 7, 9
};
BAInit(&p,(unsigned int)-1);
for (i = 0; i < sizeof(array) / sizeof(unsigned int); i++) {
Set1(&p, array[i]);
}
printf("%d\n",Find(&p,5));
printf("%d\n",Find(&p,6));
}
2.布隆过滤器:
它也是处理数据是存在还是不存在的工具。
以下是它的伪代码,这个一般不会写代码,只要了解过程即可。
typedef int Key;
typedef int(*Hashfunc)(Key);
typedef struct BloomFilter{
BitArray bitarray;
Hashfunc hashfunc1;
Hashfunc hashfunc2;
Hashfunc hashfunc3;
}BloomFilter;
int hashfunc1(Key key)
{
return key;
}
int hashfunc2(Key key)
{
return key;
}
int hashfunc3(Key key)
{
return key;
}
void InsertR(BloomFilter *pBF,uint32_t n)
{
int a1=pBF->hashfunc1(n);
int a2=pBF->hashfunc2(n);
int a3=pBF->hashfunc3(n);
Set1(&(pBF->bitarray),a1);
Set1(&(pBF->bitarray),a2);
Set1(&(pBF->bitarray),a3);
}
int FindR(BloomFilter *pBF,uint32_t n)
{
int a1=pBF->hashfunc1(n);
int a2=pBF->hashfunc2(n);
int a3=pBF->hashfunc3(n);
int b1=Find(&(pBF->bitarray),a1);
int b2=Find(&(pBF->bitarray),a1);
int b3=Find(&(pBF->bitarray),a1);
if(b1 && b2 && b3)
{
return 0;
}
return -1;
}
3.接下来做一些面试题
(1)将两个有序链表合成一个有序链表:
//合并两个有序链表。
SListNode *ListHB(SListNode *pFirst1,SListNode *pFirst2)
{
SListNode *p1=pFirst1; //分别定义两个指针指向两个链表的头结点。
SListNode *p2=pFirst2;
SListNode *NoEmpty;
SListNode *p3=(SListNode *)malloc(sizeof(SListNode)); //开辟空间用来插入。
int n=0;
while(p1!=NULL && p2!=NULL) //当不为空时。
{
if(p1->data<=p2->data) //如果第一个小于第二个。
{
if(n==0){ //第一次用普通法插
p3->data=p1->data;
p3->pNext=NULL;
n++;
}else{
SListPushBack1(&p3,p1->data); //以后进行尾插即可。
p1=p1->pNext;
}
}
else{
if(n==0){ //同理如上。
p3->data=p2->data;
p3->pNext=NULL;
n++;
}else{
SListPushBack1(&p3,p2->data);
}
p2=p2->pNext;
}
}
NoEmpty=p1; //假设p1没空。
if(p1==NULL) //如果p1为空,则令p2不空。
{
NoEmpty=p2;
}
while(NoEmpty)
{
SListPushBack(&p3,NoEmpty->data); //这是将没空的链表后续的节点继续尾插到新空间里。
NoEmpty=NoEmpty->pNext;
}
for(p3=p3;p3!=NULL;p3=p3->pNext) //输出新链表的值。
{
printf("%d ",p3->data);
}
printf("\n");
return p3;
}
(2)链表的冒泡排序:
void Sort(SListNode *pFirst) //冒泡排序
{
SListNode *p=pFirst; //定义两个节点。,一个指向头结点,一个指向空。
SListNode *q=NULL;
while(p!=q){ //总循环就是从头往后到排好序的节点。
while(p->pNext!=q)
{
if(p->data >p->pNext->data) //如果前面节点大于后面节点,进行交换。
{
swap(&(p->data),&(p->pNext->data));
}
p=p->pNext; //并且p节点也往后走。
}
q=p; //循环出来后p就是最后一个节点,让q指向它,因为它已经是最大的了。
p=pFirst; //还要记得将p重新指向头结点。
}
for(p=pFirst;p!=NULL;p=p->pNext)
{
printf("%d ",p->data); //打印从小到大的数据。
}
printf("\n");
}