哈希的位图及一些算法的面试题练习

上次介绍了哈希的开闭散列,其实它还有位图以及布隆过滤器。

1.位图:

它还是分类,十分适合处理大数据量的问题。它是将数组分为好几块,每一块是所求数据类型的比特位大小。通过看比特位上是否为1,知道它是否存在。以下是它的基本用法:

#pragma once

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<Windows.h>

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");
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值