**
从我自己博客粘贴过来的,这里没图
**
原文地址:https://kongping.net/blog/post/2788/
线性结构
1. 内存连续
2. 下标访问,时间复杂度为O(1)
链式结构
1. 内存不连续,更灵活
线性结构和链式结构比较
空间上:线性表连续,链式结构不连续,灵活度大,但是更消耗资源(因为每一个节点都需要保存节点指针)
时间上:
结构 增
删 查
线性表 O(n) O(n) O(1)
链表 O(1) O(n) O(n)
抽象数据类型ADT
Abstract Data Type:包括数据和方法(操作数据)
用python实现一个Array数组
‘’’
定义一个数组类型
data:
size: 数组最大的长度
_items: 保存数据的容器
method:
add: 增加数据
remove: 删除数组中某一个数
clear: 清空数组
‘’’
class Array(object):
def __init__(self, maxsize=32):
self.maxsize = maxsize # 数组的最大长度
self._items = [None] * maxsize
def __len__(self):
return len(self._items)
def __getitem__(self, index):
return self._items[index]
def __setitem__(self, index, value):
self._items[index] = value
def remove(self, value):
index = None # 记录被删元素的下标
for i in range(len(self)):
if self._items[i] == value:
index = i
if index is not None and i < len(self) - 1:
self._items[i] = self._items[i+1]
def clear(self):
for i in range(len(self)):
self._items[i] = None
def __iter__(self):
for item in self._items:
yield item
def test_array():
arr = Array(8)
arr[0] = 1
arr[1] = 2
arr[2] = 3
assert len(arr) == 8
assert arr[0] == 1
arr.clear()
assert arr[0] is None
# assert 0 # 判断以上代码是不是真的执行了
if name == ‘main’:
test_array()
用pytest 执行效果如下:
说明:由于删除数组元素需要维护顺序结构,所以删除的时间复杂度为O(n)
单链表
抽象数据类型:
‘’’
单链表的实现
Data: Node 节点 # 数据由节点组成
maxsize: 链表的最大长度
root: 根节点
tailnode: 尾节点
length: 链表的长度
method:
init: 初始化链表
append: 增加节点
appendleft: 在链表左侧增加节点
remove: 删除节点
popleft: 从左侧删除节点
clear: 清空链表
find: 查找元素,返回是第几个元素
‘’’
class Node(object):
def init(self, value=None, next=None):
self.value = value
self.next = next
class LinkedList(object):
def init(self, maxsize=None):
‘’‘初始化链表,如果不指定maxsize则可以无限存储’’’
self.maxsize = maxsize
node = Node()
self.root = node
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=value)
if self.tailnode is None: # 如果链表为空链表
self.tailnode = node
self.root.next = node
else:
self.tailnode.next = node
self.tailnode = 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)
headnode = self.root.next # 获取头结点
if headnode is not None:
node.next = headnode
self.root.next = node
# 如果头结点为空,说明是空链表
else:
self.root.next = node
self.tailnode = node
self.length += 1
def iter_node(self):
'''遍历节点'''
curnode = self.root.next # 第一个节点为当前节点
while curnode is not self.tailnode: # 如果不是尾节点则一直向后遍历
yield curnode
curnode = curnode.next
yield curnode # 再返回尾节点
def remove(self, value):
'''删除节点'''
prenode = self.root # 记录当前节点的前一个节点
curnode = self.root.next # 当前节点
while curnode.next is not None:
if curnode.next is None: # 如果是最后一个节点被删除,需要把尾节点往前指
self.tailnode = prenode
if curnode.value == value: # 遍历到了该节点
prenode.next = curnode.next
del curnode
self.length -= 1
return
# 否则继续遍历
prenode = curnode
curnode =curnode.next
def popleft(self):
'''删除头结点'''
headnode = self.root.next
if headnode is None: # 如果头结点为空说明链表为空
raise Exception('pop in empty linkedlist')
self.root.next = headnode.next
del headnode
self.length -= 1
return headnode.value
def clear(self):
for node in self.iter_node(): # 遍历删除节点
del node
self.tailnode = None
self.root.next = None
self.length = 0
def __iter__(self):
for node in self.iter_node():
if node is not None:
yield node.value
def find(self, value):
index = 0
for node in self.iter_node():
if node.value == value:
return index
index += 1
return -1
def test_linked_list():
ll = LinkedList()
ll.append(1)
ll.append(2)
ll.append(3)
assert list(ll) == [1, 2, 3]
ll.appendleft(-1)
assert list(ll) == [-1, 1, 2, 3]
ll.remove(2)
assert list(ll) == [-1, 1, 3]
v = ll.popleft()
assert v == -1
assert ll.find(1) == 0
ll.clear()
assert list(ll) == []
说明:由于每次查找,删除都需要遍历,所以单链表的删除和查找的时间复杂度都为O(1)
而且只能单向遍历,所以引入的双向链表
循环双端链表
循环双端链表:
每一个节点包含三个域,从上到下分别指向前一个节点,节点的值,指向下一个节点,而根节点的前一个节点为尾节点,尾节点的下一个节点为根节点,构成闭环。
抽象数据类型 :
‘’’
循环双端链表
‘’’
class Node(object):
‘’‘定义节点类型’’’
def init(self, prev=None, value=None, next=None):
self.prev, self.value, self.next = prev, value, next
class CircleDoubleLinkedList(object):
def init(self, maxsize=None):
self.maxsize = maxsize
self.length = 0
node = Node()
self.root = node
self.root.prev, self.root.next = node, node # 根节点指向自己,形成闭环
def __len__(self):
return self.length
def tailnode(self):
return self.root.prev # 根节点的前一个节点
def headnode(self):
return self.root.next # 根节点的后一个节点
def append(self, value):
if self.maxsize is not None and len(self) >= self.maxsize:
raise Exception('链表满了')
node = Node(value=value)
node.prev = self.tailnode()
self.tailnode().next = node
self.root.prev = node
node.next = self.root
self.length += 1
def appendleft(self, value):
if self.maxsize is not None and len(self) >= self.maxsize:
raise Exception('链表满了')
node = Node(value=value)
headnode = self.headnode()
headnode.prev = node
node.next = headnode
self.root.next = node
node.prev = self.root
self.length += 1
def remove(self, node): # 传入节点 O(1)
prevnode = node.prev
nextnode = node.next
prevnode.next = node.next
nextnode.prev = node.prev
del node
self.length -= 1
def iter_node(self):
curnode = self.headnode()
while curnode is not self.root:
yield curnode
curnode = curnode.next
def __iter__(self):
for node in self.iter_node():
yield node.value
def iter_node_reverse(self):
curnode = self.tailnode()
while curnode.prev is not self.root:
yield curnode
def test_circle_double_linked_list():
cdll = CircleDoubleLinkedList()
cdll.append(1)
cdll.append(2)
cdll.append(3)
cdll.append(4)
assert list(cdll) == [1, 2, 3, 4]
cdll.appendleft(0)
assert list(cdll) == [0, 1, 2, 3, 4]
代码:https://github.com/yiouejv/python_data_stract_algorithm/tree/master/linklist