Recitation- 002

64 阅读3分钟

Array sequence:

set_at and get_at only need O(1)O(1)time,but delete and insert needs linearO(n)O(n)time.We need to move the items and resize the array.

class Array_Seq:
    def __init__(self):
        self.A = []
        self.size = 0

    def __len__(self):
        return self.size()

    def __iter__(self):
        yield from self.A

    def build(self, X):
        self.A = [a for a in X]
        self.size = len(self.A)

    def get_at(self, i):
        return self.A[i]

    def set_at(self, i, x):
        self.A[i] = x

    def _copy_forward(self, i, n, A, j):
        for k in range(n):
            A[j + k] = self.A[i + k]

    def _copy_backward(self, i, n, A, j):
        for k in range(n - 1, -1, -1):
            A[j + k] = self.A[i + k]

    def insert_at(self, i, x):
        n = len(self)
        A = [None] * (n + 1)
        self._copy_forward(0, i, A, 0)
        A[i] = x
        self._copy_forward(i, n - i, A, i + 1)
        self.build(A)

    def delete_at(self, i):
        n = len(self)
        A = [None] * (n - 1)
        self._copy_forward(0, i, A, 0)
        x = self.A[i]
        self._copy_forward(i + 1, n - i - 1, i)
        self.build(A)
        return x

The key operation is the defination: copy_forward.We need to resize the array

Linked List

A linked note stores an item in a node,instead of allocating a contiguous chunk of memory
node.item stores the item,and the node.next stores the memory address of next node

class Linked_list_node:W
    def _init_(self, x):
        self.item = x
        self.next = None

    def later_node(self, i):
        if i == 0: return self
        assert self.next
        return self.next.later_node(i - 1)

Link list are more flexible sometimes ,because the constituent items can be stored anywhere.

Adventures:

easy to add or delete some items,and add a new item at the front takes O(1)time

disadventures:

hard to find some items,if the item is at the end,it will take O(n) time.

class Linked_List_Seq:
    def __init__(self):
        self.head = None
        self.size = 0

    def __len__(self):
        return self.size

    def __iter__(self):
        node = self.head
        while node:
            yield node.item
            node = node.next

    def build(self, X):
        for a in reversed(X):
            self.insert_first(a)

    def later_node(self, i):
        if i == 0: return self
        assert self.next
        return self.later_node(i - 1)

    def get_at(self, i):
        node = self.head.later_node(i)
        return node.item

    def set_at(self, i, x):
        node = self.head.later_node(i)
        node.item = x

    def insert_first(self, x):
        new_node = Linked_List_Seq(x)
        new_node.next = self.head
        self.head = new_node
        self.size += 1

    def delete_first(self):
        x = self.head.item
        self.head = self.head.next
        self.size -= 1
        return x

    def insert_at(self, i, x):
        if i == 0:
            self.insert_first(x)
            return
        new_node = Linked_List_Seq(x)
        node = self.head.later_node(i - 1)
        new_node.next = node.next
        node.next = new_node
        self.size += 1

    def delete_at(self, i):
        if i == 0:
            return self.delete_first()
        node = self.head.later_node(i - 1)
        x = node.next.item
        node.next = node.next.next
        self.size -= 1
        return x

The key operation is the def insert_at and delete_at

Dynamic Array:

class Dynamic_Array_Seq(Array_Seq):
    def __init__(self,r):
        super().__init__()
        self.size=0
        self.r=r
        self.coupute_bounds()
        self.resize(0)
    def __len__(self):
        return self.size
    def __iter__(self):
        for i in range(len(self)):
            yield self.A[i]
    def build(self,X):
        for a in X:
            self.insert_last(a)
    def compute_bounds(self):
        self.upper=len(self.A)
        self.lower=len(self.A)//(self.r*self.r)
    # 当元素达到数组的上界时,需要拓展数组容量
    # 低于下界时,进行缩容以节省空间
    # self.lower=len(self.A)//(self.r*self.r)为什么除以r^2是为了令下界尽可能的小
    def _resize(self,n):
        if (self.lower<n<self.upper): return
        m=max(n,1)*self.r
        A=[None]*m
        self._copy_forward(0,self.size,A,0)
        self.A=A
        self.compute_bounds()
    def insert_last(self,x):
        self._resize(self.size+1)
        self.A[self.size]=x
        self.size+=1
    def delete_last(self,x):
        self.A[size-1]=None
        self.size-=1
        self._resize(self.size)
    def insert_at(self,i,x):
        self.insert_last(None)
        self._copy_backward(i,self.size-(i+1),A,i+1)
        # forward 还是backward
        self.A[i]=x
    # 先将数组多预留出来一个位置即insert_last(None)
    # 从编号为i的元素开始向后移动self.size()-(i+1)个元素
    def delete_at(self,i):
        x=self.A[i]
        self._copy_forward(i+1,self.size()-(i+1),self.A,i)
        self.deleet_last
        return x

Exercises:

Given a data structure implementing the Sequence interface, show how to use it to implement the Set interface. (Your implementation does not need to be efficient.)

Solution:

思路:将Sequence中的元素逐一添加到Set中,但是当插入时,我们要进行检查,检查该元素是否在Set中已经存在过。
Sequence相对于Set独有的性质是其具有 有序性,所以我们利用这个性质即可实现Set  interfaceSet \; interface

def Set_from_Sequence(seq):
    class set_from_sequence:
        def __init__(self):
            self.S = seq()

        def __len__(self):
            return len(self.S)

        def __iter__(self):
            yield from self.S

        def build(self, A):
            self.S.build(A)

        def insert(self, x):
            for i in range(len(self.S)):
                if self.S.get_at(i).key == x.key:
                    self.S.set_at(i, x)  # 如果Set中存在这个元素的key,那么进行替换
                    return
            self.S.insert_last(x)  # 如果不存在这个key,那么直接在最后进行插入即可

        def delete(self, k):
            for i in range(len(self.S)):
                if self.S.get_at(i) == k:
                    return self.delete_at(i)

        def find(self, k):
            for x in self:
                if x.key == k:
                    return x
                return None

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

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

        def find_next(self, k):  # 寻找键值为k的下一位元素
            out = None
            for x in range(self):
                if (x.key > k):
                    if (out == None) or (x.key < out.key):
                        out = x
            return out

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

        def iter_ord(self):
            x = self.find_min()
            while x:
                yield x
                x = self.find_prev(x.key)

    return set_from_sequence