1.数组列表
内存连续 下标访问
- 列表为线性结构 内存是连续的,通过下标访问
- 链表是链式结构,内存不是连续的,需要用指针节点访问其地址
method:
class Array(object)
构造一个空列表init(self,size=32)
初始化列表变量getitem(self,index)
获取列表值的下标setitem(self,index,value)
构造列表元素
获取列表下标值与值对应len(self)
获取列表的长度clear(self,value = None)
清空列表,将None值赋予每一个列表的值iter(self)
遍历列表返回列表值zzz
实例代码块
#在一个函数中,程序执行到yield语句的时候,
# 程序暂停,返回yield后面表达式的值,在下一次调用的时候,
# 从yield语句暂停的地方继续执行,如此循环,直到函数执行完
# -*- coding:utf-8 -*-
#数组 列表 的数据结构
class Array(object):
def __init__(self,size=32):
self._size = size
#初始化一个_items列表,长度为size,列表值全部为None
self._items = [None] * size
def __getitem__(self,index):
#获取列表值的下标
return self._items[index]
#处理列表值的方法
def __setitem__(self,index,value):
#数组列表下标值与值对应
self._items[index] = value
def __len__(self):
#len方法返回数组的长度值
return self._size
#clear方法用于清除数组,默认形参value为None
def clear(self,value = None):
#遍历数组将所有值都赋予None
for i in range(len(self._items)):
self._items[i] = value
def __iter__(self):
for item in self._items:
#单测
def test_array():
size = 30
a = Array(size)
a[0] = 1
#assert单测 a[0]是否为1 如果结果非真则引发一个错误
assert a[0] == 1
a.clear()
assert a[0] is None
2.单链表
初始化链表root(根节点)->Tail(尾节点)
if root.next is None(则该链表为空)
if root.next is not None:
(入口)root->Head->节点1->节点2->...->Tail
节点Node-->value/next (数据域/指针域)
单链表 -->
1.data -->
1.root节点
2.length长度
2.method -->
1. class Node(object)
构造节点的模块
2. class LinkedList(object)
构造链表的模块
3. __init__(self,maxsize=None)
初始化变量的函数
4. __len__(self)
返回链表长度函数
5. append(self,value)
在链表尾部添加新节点
6. appendleft(self,value)
在链表头部添加新节点
7. iter_node(self)
遍历链表节点方法
8. __iter__(self)
遍历链表节点值方法
9. remove(self,value)
删除节点函数
10. find(self,value)
查找节点函数
11. popleft(self)
从链表头部删除节点
12. clear(self)
清空链表方法
实例代码块
# -*- coding:utf-8 -*-
#初始化一个节点 模块
class Node(object):
def __init__(self,value=None,next=None):
self.value,self.next = value,next
#创建链表 模块
class LinkedList(object):
#初始化maxsize=None 将此链表最大容量默认为无穷大
def __init__(self,maxsize=None):
self.maxsize = maxsize
#初始化一个根节点
self.root = Node()
#初始化链表长度为0
self.length = 0
#初始化尾节点为None
self.tailnode = None
#定义函数返回链表长度
def __len__(self):
return self.length
"""
value为形参,函数实现在链表末尾插入一个节点,
(如果tailnode为None)root->node(插入node)
(如果tailnode不为None)root->tailnode->node(插入node)
"""
def append(self,value):
if self.maxsize is not None and len(self) > self.maxsize:
#抛出异常
raise Exception('Full')
#构造一个新的节点
node = Node(value)
#取值tailnode
tailnode = self.tailnode
if tailnode is None:
self.root.next = node
else:
tailnode.next = node
#更新tailnode,将插入的node标记为最后一个节点
self.tailnode = node
self.length += 1
"""
在链表头部插入节点:
root->node(插入的新节点)->headnode
root->next = node
node->next = headnode
"""
def appendleft(self,value):
headnode = self.root.next
node = Node(value)
self.root.next = node
node.next = headnode
self.length += 1
"""
遍历首节点到尾节点:
当curnode.next = tailnode时跳出循环,
此时yield curnode就是单独返回尾节点
"""
def iter_node(self):
curnode = self.root.next
while curnode is not self.tailnode:
yield curnode
curnode = curnode.next
yield curnode
#遍历链表节点值
def __iter__(self):
for node in self.iter_node():
yield node.value
"""
删除节点操作:
原理:找到要删除的节点,将其前面一个节点的下一个节点指向删除节点的下一个节点
prevnode.next = node(预备删除节点).next
操作:
定义curnode为根节点下一个节点
遍历链表查找指定要删除的节点,找到后
将其前一个节点的指针指向其后一个节点的地址
"""
def remove(self,value): #O(n)
prevnode = self.root
curnode = self.root.next
while curnode.next is not None:
if curnode.value == value:
prevnode.next = curnode.next
del curnode
self.length -= 1
return
"""
查找节点操作:
定义一个变量初始化为0,遍历链表
找到指定节点后返回变量值,表明这是第几个节点
如果未找到则返回-1
"""
def find(self,value): #O(n)
index = 0
for node in self.iter_node():
if node.value == value:
return index
index += 1
return -1
"""
从链表头部删除节点:
root->节点1->节点2->...->尾节点
1.headnode = root.next
2.root.next = headnode.next
3.获取headnode的值
4.del headnode
"""
def popleft(self): #O(n)
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
del headnode
return value
#清空链表:遍历链表将其所有节点赋值为None,将其长度赋值为0
def clear(self):
for node in self.iter_node():
del node
self.root.next = None
self.length = 0
#单测
def test_linked_list():
#创建一个链表的实例ll
ll = LinkedList()
ll.append(0)
ll.append(1)
ll.append(2)
#断言 判断assert后面的表达式是否相等,相等则返回真,否则返回错误信息
assert len(ll) == 3
assert ll.find(2) == 2
assert ll.find(3) == -1
ll.remove(0)
assert len(ll) == 2
assert ll.find(0) == -1
assert list(ll) == [1,2]
ll.appendleft(0)
assert list(ll) == [0,1,2]
assert len(ll) == 3
headvalue = ll.popleft()
assert headvalue == 0
assert len(ll) == 2
assert list(ll) == [1,2]
ll.clear()
assert len(ll) == 0
3.双端链表
root/prev/next -> Head/prev/next -> node2/prev/next -> node3/prev/next -> Tail/prev/next
循环遍历:
root.prev = Tail.nextdata域:
root maxsize length
指针域:
prev next
method:
1.class Node(object)
构造节点的模块
2.class CircualDoubleLinedList(object)
构造链表的模块
3. __init__(self,maxsize=None)
初始化变量的函数
4. __len__(self)
返回链表长度的函数
5. headnode(self)
构造一个headnode
6. tailnode(self)
构造一个tailnode
7. append(self,value)
在链表尾部插入新节点
8. appendleft(self,value)
在链表头部插入新节点
9. remove(self,node)
删除节点函数
10. iter_node(self)
遍历链表节点函数
11. __iter__(self)
遍历链表节点值函数
12. iter_node_reverse(self)
反向遍历链表节点值函数
实例代码块
# -*- coding:utf-8 -*-
class Node(object):
def __init__(self,value=None,prev=None,next=None):
self.value,self.prev,self.next = value,prev,next
"""
初始化构造一个node,将其前后指针都指向自己,
形成闭环,再将其赋值给root
"""
class CircualDoubleLinedList(object):
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
#构造headnode函数
def headnode(self):
return self.root.next
#构造tailnode函数
def tailnode(self):
return self.root.prev
"""
root->node1->node2->tailnode 新增node
"""
def append(self,value):
if self.maxsize is not None and len(self) > self.maxsize:
raise Exception('FULL')
node = Node(value=value)
tailnode = self.tailnode()
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('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
"""
删除节点:
需要对空链表情况进行分析
1.将指定删除的节点node的前一个节点指向node->next
2.将指定删除的节点node的后一个节点指向node->prev
"""
def remove(self,node):
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
"""
for循环遍历链表的值
"""
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
#单测
def test_double_link_list():
dll = CircualDoubleLinedList()
assert len(dll) == 0
dll.append(0)
dll.append(1)
dll.append(2)
assert list(dll) == [0,1,2]
assert [node.value for node in dll.iter_node()] == [0,1,2]
assert [node.value for node in dll.iter_node_reverse()] == [2,1,0]
headnode = dll.headnode()
assert headnode.value == 0
dll.remove(headnode)
assert len(dll) == 2
assert [node.value for node in dll.iter_node()] == [1,2]
dll.appendleft(0)
assert [node.value for node in dll.iter_node()] == [0,1,2]
4.队列
队列特点:
1.先进先出,后入后出
-----------------------------------
---> 5 4 3 2 1 ---> FIFO 结构
-----------------------------------
数组实现队列原理
---->数组实现队列原理:<----
0->10依次放入列表,
新添加一个元素,head指针+1
tail指针指向列表第一个元素,每执行出列操作tail值+1,指向第二个元素...
head head head head head head ...
------------------------------------------------
0 1 2 3 4 5 6
------------------------------------------------
tail tail tail tail tail tail ...
实例代码块
# -*- coding:utf-8 -*-
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
#################################################
# 下面是 Queue 实现 数组实现队列
#################################################
class FullError(Exception):
pass
class ArrayQueue(object):
def __init__(self,maxsize):
self.maxsize = maxsize
self.array = Array(maxsize)
self.head = 0
self.tail = 0
def push(self,value):
if len(self) >= self.maxsize:
raise FullError('queue full')
self.array[self.head % self.maxsize] = value
self.head += 1
def pop(self):
value = self.array[self.tail % self.maxsize]
self.tail += 1
return value
def __len__(self):
return self.head - self.tail
def test_array_queue():
import pytest
size = 5
q = ArrayQueue(size)
for i in range(size):
q.push(i)
with pytest.raises(FullError) as excinfo:
q.push(size)
assert 'full' in str(excinfo.value)
assert len(q) == size
assert q.pop() == 0
assert q.pop() == 1
q.push(5)
assert len(q) == 4
assert q.pop() == 2
assert q.pop() == 3
assert q.pop() == 4
assert q.pop() == 5
assert len(q) == 0
单链表实现队列原理
从0->5依次插入链表,调用append函数从链表尾部插入
append(value)
--------------------------------------
0 1 2 3 4 5
--------------------------------------
popleft()
先入:append
先出:popleft
代码实例块
# -*- coding:utf-8 -*-
class Node(object):
def __init__(self,value=None,next=None):
self.value,self.next = value,next
class LinkedList(object):
def __init__(self,maxsize=None):
self.maxsize = maxsize
self.root = Node()
self.length = 0
self.tailnode = None
def __len__(self):
return self.length
def append(self,value):
if self.maxsize is not None and len(self) > self.maxsize:
raise Exception('Full')
node = Node(value)
tailnode = self.tailnode
if tailnode is None:
self.root.next = node
else:
tailnode.next = node
self.tailnode = node
self.length += 1
def appendleft(self,value):
headnode = self.root.next
node = Node(value)
self.root.next = node
node.next = headnode
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 __iter__(self):
for node in self.iter_node():
yield node.value
def remove(self,value): #O(n)
prevnode = self.root
curnode = self.root.next
while curnode.next is not None:
if curnode.value == value:
prevnode.next = curnode.next
del curnode
self.length -= 1
return
def find(self,value): #O(n)
index = 0
for node in self.iter_node():
if node.value == value:
return index
index += 1
return -1
def popleft(self): #O(n)
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
del headnode
return value
def clear(self):
for node in self.iter_node():
del node
self.root.next = None
self.length = 0
#################################################
# 下面是 Queue 实现 单链表实现队列
#################################################
class FullError(Exception):
pass
class EmptyError(Exception):
pass
class Queue(object):
def __init__(self,maxsize=None):
self.maxsize = maxsize
self._item_linked_list = LinkedList()
def __len__(self):
return len(self._item_linked_list)
def push(self,value):
if self.maxsize is not None and len(self) >= self.maxsize:
raise FullError('Queue full')
return self._item_linked_list.append(value)
def pop(self):
if len(self) <= 0:
raise EmptyError('Queue empty')
return self._item_linked_list.popleft()
def test_queue():
q = Queue()
q.push(0)
q.push(1)
q.push(2)
assert len(q) == 3
assert q.pop() == 0
assert q.pop() == 1
assert q.pop() == 2
assert len(q) == 0
import pytest
with pytest.raises(EmptyError) as excinfo:
q.pop() #raise EmptyError
assert 'empty' in str(excinfo.value)
未完待续…