python数据结构与算法——(一)数组列表和链表

同步发布在github.io博客

1. 数组和列表(线性结构)

线性结构特点:

  • 内存连续
  • 下标访问

数组和列表都属于线性结构。

1.1 数组

python内置的array:只能存同一数据类型(数值、字符)

1.2 列表

操作 平均时间复杂度
list[index] O(1)
list.append O(1)
list.insert O(n)
list.pop(index),default last element O(1)
list.remove O(n)

1.3 用list实现Array ADT

ADT: Abstact Data Type, 抽象数据类型,在组合已有的数据结构来实现一种新的数据类型中,ADT定义了类型的数据和操作。python内置的list可以看成一种抽象数据类型。

class Array(object):
	def __init__(self,size=32):
		self._size = size 
		self._items = [None]*size
	
	def __getitem__(self,index):
		return self._items[index]
	
	def __setitem__(self,index,value):
		self._items[index] = value
	
	def __len__(self):
		return self._size 
	
	def clear(self, value=None):
		for i in range(len(self._items)):
			self._items[i] = value
	
	def __iter__(self):
		for item in self._items:
			yield item

详细代码见github:array_and_list.py

2. 链表(链式结构)

链式结构与线性结构区别:

  • 内存不连续(因此需要每个链接表的节点保存一个指向下一个节点的指针)
  • 不能通过下标随机访问
  • 查找元素需要从头遍历

2.1 单链表

2.1.1 时间复杂度

链表操作 平均时间复杂度
linked_list.append(value) O(1)
linked_list.appendleft(value) O(1)
linked_list.find(value) O(n)
linked_list.remove(value) O(n)

2.1.2 实现

定义一个单链表的节点:

class Node(object):
    """
    一个链接表的节点,有两个属性:值;保存下一个节点的位置。
    """
    def __init__(self, value=None, next=None):
	    self.value = None 
	    self.next = None 

单链表 LinkedList ADT:

class LinkedList(object):
    """ 链接表 ADT
    [root] -> [node0] -> [node1] -> [node2]
    """

    def __init__(self, maxsize=None):
        """
        :param maxsize: int or None, 如果是None, 无限扩充
        """
        self.maxsize = None
        self.root = Node()  # 默认root节点指向None
        self.tailnode = None
        self.length = 0

    def __len__(self):
        return self.length

    def append(self, value):
        if self.maxsize is not None and len(self) >= self.maxsize:
            raise Exception('LinkedList is Full')
        node = Node(value)  # 构造节点
        tailnode = self.tailnode
        if tailnode is None:  # length=0时,追加到root后
            self.root.next = node
        else:
            tailnode.next = node
        self.tailnode = node  # 更新tailnode
        self.length += 1

    def appendleft(self, value):
        if self.maxsize is not None and len(self) >= self.maxsize:
            raise Exception('LinkedList is Full')
        node = Node(value)
        if self.tailnode is None:
	        self.tailnode = node
        headnode = self.root.next
        self.root.next = node
        node.next = headnode
        self.length += 1

    def iter_node(self):
        """
        遍历从head节点到tail节点
        """
        curnode = self.root.next
        while curnode is not self.tailnode:  # 从第一个节点开始遍历
            yield curnode
            curnode = curnode.next  # 移动到下一个节点
        if curnode is not None:
            yield curnode

    def __iter__(self):
        for node in self.iter_node():
            yield node.value

    def remove(self, value):
        """
        删除包含值的一个节点,将其前一个节点的next指向被查询节点的下一个
        """
        prevnode = self.root
        for curnode in self.iter_node():
            if curnode.value == value:
                prevnode.next = curnode.next
                if curnode is self.tailnode:
                    self.tailnode = prevnode  # 更新tailnode
                del curnode
                self.length -= 1
                return 1  # 删除成功
            else:
                prevnode = curnode
        return -1  # 表明删除失败

    def find(self, value):
        """
        查找一个节点,返回序号,从0开始
        """
        index = 0
        for node in self.iter_node():
            if node.value == value:
                return index  # 找到
            index += 1
        return -1  # 没找到

    def popleft(self):
        """
        删除第一个链表节点
        """
        if self.root.next is None:
            raise Exception('pop from empty LinkedList')
        headnode = self.root.next
        self.root.next = headnode.next
        self.length -= 1
        value = headnode.value

        if self.tailnode is headnode:  # 单节点删除 tailnode处理
            self.tailnode = None
        del headnode
        return value

    def insert(self, index, value):
        """
        在指定位置插入节点
        """
        if self.root == None:
            return
        if index <= 0: # 等于在链表头部插入一个元素
            self.appendleft(value)
        elif index >= len(self) : #等于在链表尾部插入一个元素
            self.append(value)
        else: # 在链表中间插入
            node = Node(value)
            count = 0
            prevnode = self.root
            for curnode in self.iter_node():
                if count == index:
                    prevnode.next = node
                    node.next = curnode
                    self.length += 1
                else:
                    prevnode = curnode
                count += 1

    def replace(self, value, new_value):
        """
        替换节点的值
        """
        index = 0
        for node in self.iter_node():
            if node.value == value:
                node.value = new_value
                return index
            index += 1
        return -1 #没有找到该值
        
    def clear(self):
        for node in self.iter_node():
            del node
        self.root.next = None
        self.length = 0
        self.tailnode = None

详细代码见github:linked_list.py

2.2 双链表

2.2.1 与单链表的区别

单链表的缺点:find和remove都是O(n),因为无论是查找还是删除,都需要先查找,而单链表的查找只能从头顺着找到尾。
相比于单链表,双链表每个节点既保存了指向下一个节点的指针,也保存了上一个节点的指针。优势如下:

  • 将root的prev指向tail节点,就能将整个串起来形成循环
  • 通过告诉某个节点,删除该节点,复杂度为O(1)(PS:如果给的是值,还是需要先查找,O(n))

2.2.2 时间复杂度

循环双链表操作 平均时间复杂度
cdll.append(value) O(1)
cdll.appendleft(value) O(1)
cdll.remove(node),注意这里参数是node O(1)
cdll.headnode() O(1)
cdll.tailnode() O(1)

2.2.3 实现

定义一个双链表的节点:

class Node(object):
    def __init__(self, value=None, prev=None, next=None):
        self.value, self.prev, self.next = value, prev, next

双链表 CircularDoubleLinkedList ADT:

class CircularDoubleLinkedList(object):
    """
    循环双链表 ADT
    所谓循环,就是通过root的prev指向tail节点将整个串起来
    """

    def __init__(self, maxsize=None):
        self.maxsize = maxsize
        node = Node()
        node.next, node.prev = node, node
        self.root = node
        self.length = 0

    def __len__(self):
        return self.length

    def headnode(self):
        return self.root.next

    def tailnode(self):
        return self.root.prev

    def append(self,value): #O(1)
        if self.maxsize is not None and len(self) >= self.maxsize:
            raise Exception('LinkedList is Full')
        node = Node(value=value)
        tailnode = self.tailnode() or self.root

        tailnode.next = node
        node.prev = tailnode
        node.next = self.root
        self.root.prev = node
        self.length += 1

    def appendleft(self, value):
        if self.maxsize is not None and len(self) >= self.maxsize:
            raise Exception('LinkedList is Full')
        node = Node(value=value)
        if self.root.next is self.root: # empty的情况
            node.next = self.root
            node.prev = self.root
            self.root.next = node
            self.root.prev = node
        else:
            node.prev = self.root
            headnode = self.root.next
            node.next = headnode
            headnode.prev = node
            self.root.next = node
        self.length += 1

    def remove(self, node): # 传入参数为node时为O(1)
        if node is self.root:
            return
        else:
            node.prev.next = node.next
            node.next.prev = node.prev
        self.length -= 1
        return node

    def iter_node(self):
        if self.root.next is self.root:
            return
        curnode = self.root.next
        while curnode.next is not self.root:
            yield curnode
            curnode = curnode.next
        yield curnode

    def __iter__(self):
        for node in self.iter_node():
            yield node.value

    def iter_node_reverse(self):
        """
        区别于单链表的反序遍历
        """
        if self.root.prev is self.root:
            return
        curnode = self.root.prev
        while curnode.prev is not self.root:
            yield curnode
            curnode = curnode.prev
        yield curnode

详细代码见github:double_link_list.py

3. reference

猜你喜欢

转载自blog.csdn.net/weixin_43004311/article/details/81873158