[超水笔记之四]北大慕课:数据结构与算法Python版

散列Hashing

  • 散列
    • 基本概念
    • 区块链技术
      • 基本概念
      • 数据结构
    • 散列函数的设计
    • 冲突解决方案
    • 映射抽象数据类型

散列

基本概念

  1. 散列表(hash table哈希表)是一种数据集,其中数据项的存储方式尤其有利于将来快速的查找定位。哈希表中每一个存储位置,称为槽(slot),可以用来保存数据项,每个槽有一个唯一名称.
  2. 散列函数(hash function):实现从数据项到存储槽名称的转换
  3. 给定一组数据项,若一个散列函数能将每个数据项映射到不同槽中,则该函数称为“完美散列函数”
  4. 作为一致性校验的数据“指纹”需要具备:

压缩性 易计算性 抗修改性 抗冲突性

  1. 散列函数: MD5/SHA

1.MD5(Message Digest):将任意长度的数据变换为固定长位128位(16字节)的“摘要”

2.SHA(Secure Hash Algorithm)## 区块链技术

图片示意:
[超水笔记之四]北大慕课:数据结构与算法Python版_第1张图片
代码实现:

import hashlib
hash = hashlib.md5()
hash.update(bytes('test',encoding='utf-8'))
print(hash.hexdigest())

区块链技术

基本概念

  • 区块链是一种分布式数据库,通过网络连接的节点,每个节点都保存着整个数据库所属有数据,
    任何地点存入的数据都会完成同步

数据结构

区块链由一个个区块(block)组成,区块分为(head)和体(body)。
区块头记录了一些元数据和链接到前一个区块的信息(生成时间、前一个区块(head+body)的散列值)
区块体记录了实际数据

散列函数的设计

  1. 折叠法: 将数据项按照位数分为若干段,再将几段数字相加,最后对散列表大小求余,得到散列值
    (有时还有隔数反转步骤,提供了微调手段,以便更好符合散列特性)

  2. 平方取中: 将数据项做平方运算,然后取平方数的中间两位,再对散列表的大小求余

    例:对44进行散列

    step1: 44*44

    step2: 取中 :93

    step3: 对列表大小求余(以11为例),93%11=5

  3. 非数项:将字符串中每个字符看作ASCII码,将码值累加,对列表大小求余

    代码实现:

def hash(astring,tablesize):
    sum=0
    for pos in range(len(astring)):
        sum += ord(astring[pos])

    return sum%tablesize

冲突解决方案

  • 再找一个开放的空槽保存数据项(开放定址Open Addressing)

  • 向后逐个槽寻找的方法则是开放定址技术中的线性探测(liner probing)

  • 不足:有聚集(clustering)趋势

改进:

  1. 逐个探测 => 跳跃式探测
  • 再散列rehashing
    [超水笔记之四]北大慕课:数据结构与算法Python版_第2张图片
    1.还可将线性探测变为“二次探测quadratic probing”
    2.不再固定skip的值,而是逐步增加skip值,如1,3,5
    3.这样槽号就会是原散列值以平方数增加: h h h, h + 2 0 h+2^{0} h+20, h + 2 1 h+2^{1} h+21

  • 数据项链Chaining
    [超水笔记之四]北大慕课:数据结构与算法Python版_第3张图片

将容纳单个数据项的槽扩展为容纳数据项集合(或者对数据项链表的引用)

映射抽象数据类型

  • ADT Map定义操作

    Map() 创建空映射,返回空映射对象

    put(key,val) 将key-val关联加入映射中,若key已存在,将val替换旧关联值

    get(key) 给定key,返回关联值,若不存在,返回空

    del 通过del map[key] 形式删除key-val关联

    len() 返回映射中key-val关联数目

    in key in map 形式,返回key是否在关联中,bool类型

代码实现

class HashTable:
    # put方法
    def __init__(self):
        self.size = 11
        self.slots = [None]*self.size
        self.data = [None]*self.size

    def put(self,key,data):
        hashvalue = self.hashfunction(key)

        if self.slots[hashvalue] ==None:
            self.slots[hashvalue] = key
            self.data[hashvalue] = data
        else:
            if self.slots[hashvalue] == key:
                self.data[hashvalue] = data
            else:
                nextslot = self.rehash(hashvalue)
                while self.slots[nextslot] != None and\
                    self.slots[nextslot]!=key:
                    nextslot = self.rehash(nextslot)
                if self.slots[nextslot] == None:
                    self.slots[nextslot] = key
                    self.data[nextslot] = data
                else:
                    self.data[nextslot] = data

    def hashfunction(self,key):
        return key%self.size

    def rehash(self,oldhash):
        return (oldhash+1)%self.size

    # get方法
    def get(self,key):
        startslot = self.hashfunction(key)

        data = None
        stop = False
        found = False
        position = startslot
        while self.slots[position] != None and \
            not found and not stop:
            if self.slots[position] == key:
                found = True
                data = self.data[position]
            else:
                position = self.rehash(position)
                if position == startslot:
                    stop = True
        return data
    # ADT Map:附加代码
    # 通过特殊方法实现[]访问
    
    def __getitem__(self, key):
        return self.get(key)
    
    def __setitem__(self, key, value):
        self.put(key,data)

未完待续。。。

你可能感兴趣的:(python,数据结构)