算法第八周_位运算,布隆过滤,LRU cache,排序算法_20210120

一,位运算

位运算符
在这里插入图片描述
在这里插入图片描述
异或:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
对于X&(-X)获得最低位的1的补充内容,需要先知道负数的二进制是如何表达的,如下:

负数的二进制表示
在这里插入图片描述
参与位运算的是补码,正数的补码和源码是一样的。
计算机中的数据按补码形式存储,因此在进行位运算时,直接操作的是补码。正数的原码、反码和补码是其本身

二,布隆过滤(bloom filter)

布隆过滤和LRU cache在面试和工业界应用都比较广泛;
布隆过滤器和hash表比较类似,下面是一个对比
hash表:
对于输入的元素,经过hash函数会映射到一个index中,如果存在重复元素,就使用拉链式存储重复元素,从下图中可以看到hashtable是一个没有误差的数据结构,每个元素有多大都会完完全全的存储在hashtable中,比如电话号码这种冗余的信息都会存储在hashtable中。
不仅可以判断一个元素是否在,还可以直到其具体的信息。
在这里插入图片描述
但是在工业界中我们并不需要完全存储元素本身,而只需要直到这个元素在在我的表中到底有没有就好,这个时候bloom filter就应运而生了,
Bloom filter:
在这里插入图片描述
为什么能够远远的节省空间和时间?
一是因为其使用二进制向量表示,所以节省空间,另一方面他是模糊的查询方式。
bloom的原理:
在这里插入图片描述
现在要一次存储x,y,z三个元素,每个元素通过bloom filter的映射函数映射到二进制数的三个位置,
查询w是否在索引里面,通过映射函数计算后,得到110,有0代表说明w不在索引里面,所以我们可以判断一个元素映射后只要有一个位为0,那么这个元素是一定不在bloom 过滤器中,但是对于测试元素,如果其映射的位全部为1,我们只能说他是有可能在bloom中,比如下图中的B其实是不在bloom filter中的,但是查询结果是在的,这就不准确了,bloom一般是放在最外层当缓存使的,也就是说当作一个很快速的判断使的,当B查到在bloom中的,然后B就会继续在这台机器的数据库中查,最后查出来发现B是不存在的,查询C的时候,在bloom中是不存在的,那一定在数据库中也是不存在的,就不用去查看数据库了,节省了查询时间。因此可以发现,bloom知识挡在一台机器前面的快速查询缓存,要想真正确定这个元素是否真正存在,就需要访问机器存储数据的完整数据结构(数据库)
在这里插入图片描述

应用案例

  • 比特币网络

  • 分布式系统(Map-Reduce) — Hadoop、search engine

  • Redis 缓存

  • 垃圾邮件、评论等的过滤

科普1
科普2

bloom filter的python实现

from bitarray import bitarray   #bitarray是系统的数据结构,是一个数组,存储的是二进制位
import mmh3 

class BloomFilter: 
	def __init__(self, size, hash_num): 
		self.size = size    #数组大小
		self.hash_num = hash_num   #一个元素进来被分为多少个二进制位
		self.bit_array = bitarray(size) 
		self.bit_array.setall(0) 
		
	def add(self, s):    #添加元素
		for seed in range(self.hash_num): 
			result = mmh3.hash(s, seed) % self.size #index
			self.bit_array[result] = 1
			
	def lookup(self, s):    #查找元素
		for seed in range(self.hash_num): 
			result = mmh3.hash(s, seed) % self.size 
			if self.bit_array[result] == 0: 
				return "Nope"
		return "Probably"
bf = BloomFilter(500000, 7) 
bf.add("dantezhao") 
print (bf.lookup("dantezhao")) 
print (bf.lookup("yyj"))

python其他的实现方式1

python的其他实现方式2

三,LRU cache

缓存

inter 的三级缓存,最常用的,最先交给CPU处理的就放在L1D缓存中,次之。l1.l2.l3,再往外就是内存了。L1d到内存,处理速度递减,能够存储的数据量递增。这就是inter 处理器的缓存机制。
在这里插入图片描述

缓存介绍

扫描二维码关注公众号,回复: 12394621 查看本文章

缓存的基本特性:

在这里插入图片描述
缓存大小就像人的记忆力,究竟能够记住多少东西,
替换策略,当上一级缓存满的话是将哪些不常用的数据放到下一级缓存呢?这就是所谓的替换策略了,对于LRU cache,他的替换策略就是最近最少使用的,就将其最后淘汰,他的实现一般是使用hash表+双向链表来实现这样查询删除,修改的时间复杂度都是O(1)的。

LRU cache更新的原则

在这里插入图片描述

替换策略

• LFU - least frequently used #统计使用的频率,使用频率最少的,放在最下面,最先被淘汰

• LRU - least recently used 最近最少被使用的被淘汰掉。

替换算法总览
最新的替换算法越来越智能,不在是使用简单的逻辑,而是使用人工智能的,现在的替换算法和推荐算法有异曲同工之妙。

三,排序算法

排序算法的分类
在这里插入图片描述
比较类排序一般是直接有函数可以调用的。
比较类排序是有无法突破的时间复杂度,而我们使用中的大部分也都是这种比较类排序,
非比较类排序只能应用于整形的排序,而不能用在字符串或者对象的排序,同时是需要格外的内存空间。

排序的分类

在这里插入图片描述
非比较类排序一般是放在一个数组中,然后统计每个数字出现的次数。

排序算法对比分析

在这里插入图片描述
考察和使用较多的排序是nlog(n)时间复杂度的排序算法,即堆排序,快速排序,归并排序。

排序算法详解

对于排序算法的详细了解可以参考这篇文章:十大经典排序算法

初级排序(简单了解)

在这里插入图片描述
可以理解冒泡排序是选择排序的相反过程,选择排序是选择最小的放到前面,冒泡排序是每一次将最大的放到后面。

高级排序(重点掌握)

快速排序

在这里插入图片描述
快速排序是分治的思想:

def quick_sort(begin, end, nums):    
	if begin >= end:        
		return    
	pivot_index = partition(begin, end, nums)    
	quick_sort(begin, pivot_index-1, nums)    
	quick_sort(pivot_index+1, end, nums)    
def partition(begin, end, nums):     #这个函数的作用是选择一个pivot,将小于pivot的元素都移到pivot左侧,大于pivot的元素都移到pivot右测
	pivot = nums[begin]    
	mark = begin    
	for i in range(begin+1, end+1):        
		if nums[i] < pivot:           
			mark +=1            
			nums[mark], nums[i] = nums[i], nums[mark]    
	nums[begin], nums[mark] = nums[mark], nums[begin]    
	return mark

归并排序

在这里插入图片描述
代码:

def mergesort(nums, left, right):    
	if right <= left:        
		return    
	mid = (left+right) >> 1    
	mergesort(nums, left, mid)    
	mergesort(nums, mid+1, right)    
	merge(nums, left, mid, right)
def merge(nums, left, mid, right):    
	temp = []    
	i = left    
	j = mid+1    
	while i <= mid and j <= right:      #这里的三个while循环和合并两个有序列表有着异曲同工之妙  
		if nums[i] <= nums[j]:            
			temp.append(nums[i])            
			i +=1        
		else:            
			temp.append(nums[j])            
			j +=1    
	while i<=mid:        
		temp.append(nums[i])        
		i +=1    
	while j<=right:        
		temp.append(nums[j])        
		j +=1    
	nums[left:right+1] = temp

快速排序和归并排序的对比

在这里插入图片描述
以上两种高级排序是重点,下面介绍另外一种高级排序:堆排序
在这里插入图片描述
堆排序代码:

def heapify(parent_index, length, nums):    
	temp = nums[parent_index]    
	child_index = 2*parent_index+1    
	while child_index < length:        
		if child_index+1 < length and nums[child_index+1] > nums[child_index]:            
			child_index = child_index+1        
		if temp > nums[child_index]:            
			break        
		nums[parent_index] = nums[child_index]        
		parent_index = child_index        
		child_index = 2*parent_index + 1    
	nums[parent_index] = temp
	
def heapsort(nums):    
	for i in range((len(nums)-2)//2, -1, -1):        
		heapify(i, len(nums), nums)    
	for j in range(len(nums)-1, 0, -1):        
		nums[j], nums[0] = nums[0], nums[j]        
		heapify(0, j, nums)

特殊排序(仅作了解)

特殊排序都是可以线性时间的,但是要求数组元素都是整数
在这里插入图片描述

参考资料:
三个关于排序的动画:
6分钟看完15种排序算法动画展示
【简单明了】9种经典排序算法可视化动画
十大经典排序算法(动图演示)

猜你喜欢

转载自blog.csdn.net/a18829292719/article/details/112844027
今日推荐