MIT 6.006 recitation04

108 阅读1分钟

DirectAccessArray:

Any item x with key k will be stored in array index k.
We can find an item in O(1) time.In comparison Model,the the bramching factor is two ,so we can find the item in lognlog n time in the shortest time.
If we want a faster time to achivefind(k),we need the branching factor larger than constant w(1)w(1)

class DirectAccessArray:
    def __init__(self, u):
        self.A = [None] * u

    def find(self, k):
        return self.A[k]

    def insert(self, x):
        self.A[x.key] = x

    def delete(self, k):
        self.A[k] = None

    def find_next(self, k):
        for i in range(k, len(self.A)):
            if A[i] is not None:
                return A[i]

    def find_max(self):
        for i in range(len(self.A) - 1, -1, -1):
            if A[i] is not None:
                return A[i]

    def delete_max(self):
        for i in range(len(self.A) - 1, -1, -1):
            x = A[i]  # 用于记录并存储每一个值
            if A[i] is not None:
                A[i] = None
                return x

Hash function:

H(m,p)=((ak+b)mod  p)mod  mH(m,p)=((ak+b)mod \;p)mod\; m
The probaility that the hashes will collide is no greater than1m{\frac{1}{m}}
The number on the chain of the collided items is less than 1+1m(n1)1+{\frac{1}{m}}\cdot {(n-1}).Thus the size of the chain is O(1).

class Hash_Table_Set:
    def __init__(self, r=200):
        self.chain_set = Set_from_Seq(Linked_List_Seq)
        self.A = []
        self.size = 0
        self.r = r
        self.p = 2 ** 31 - 1
        self.a = random(1, self.p - 1)
        self.compute_bounds()
        self.resize(0)

    def __len__(self):
        return self.size

    def __iter__(self):
        for X in sefl.A:
            yield from X

    def build(self, X):
        for x in X:
            self.insert(x)


def _hash(self, k, m):
    return ((self.a * k) % self.p) % self.m


def _coupute_bounds(self):
    self.upper = self.A
    sefl.lower = self.A * 100 * 100 // (self.r * self.r)


def _resize(self, n):
    if (self.lower >= n) or (self.upper <= n):
        f = self.r // 100
        if self.r % 100: f = f + 1
        m = max(n, 1) * f
        A = [self.chain_set() for _ in range(m)]
        for x in self:
            h = self._hash(self.x, m)
            A[h].insert(x)
        self.A = A
        self._compute_bounds()


def find(self, k):
    h = self._hash(k, len(self.A))
    return self.A[h].find(k)


def insert(self, x):
    self._resize(self.size + 1)
    h = self._hash(x.key, len(self.A))
    added = self.A[h].insert(x)
    if added: self.size += 1
    return added


def delete(self, k):
    assert self.size > 0
    h = self._hash(k, len(self.A))
    x = self.A[h].delete(k)
    self.size -= 1
    self._resize(self.size)
    return x


def find_min(self):
    out = None
    for x in self:
        if (out is None) or (x.key < out.key):
            out = x
    return out


def find_max(self):
    out = None
    for x in self:
        if (out is None) or (x.key > out.key):
            out = x

    return out


def find_next(self, k):
    out = None
    for x in self:
        if x.key > k:
            if (out is None) or (x.key < out.key):
                out = x
    return out


def find_prev(self, k):
    out = None
    for x in self:
        if x.key < k:
            if (out is None) or (out.key > x.key):
                out = x
    return out


def iter_order(self):
    x = self.find_min()
    while x:
        yield x
        x = self.find_next(x.key)