之前只是对了解一些基础算法的概念,而并没有真正用代码取去实现过,所以准备在这段时间内把这些算法实现以下,第一个是单向链表,然而通过一个链表又让我想到了python的其它东西(相辅相成)。注:这里就不谈链表的概念了,只是说一说随着我脑洞大开而想到的其它东西。
好了先把我写的单链表给贴出来:
#单链表节点
class SingleNode:
def __init__(self,item):
#存放数据
self.item = item
#下个节点标识
self.next = None
#单链表实现
class SingleLL:
def __init__(self):
self._head = None
#判断链表是否为空
def is_empty(self):
return self._head == None
#返回链表长度
def length(self):
cur = self._head
count = 0
while cur != None:
count += 1
#后移一个节点
cur = cur.next
return count
# 打印链表内所有节点
def print_all(self):
cur = self._head
while cur != None:
print(cur.item)
cur = cur.next
#头部添加节点
def add(self,item):
#新的节点
node = SingleNode(item)
node.next = self._head
self._head = node
#尾部添加节点
def append(self,item):
#实例化一个节点
node = SingleNode(item)
#当为空时, _head直接指向新节点
if self.is_empty():
self._head = node
else:
#不为空,则找到最后一个节点并将其指向新节点
cur = self._head
while cur.next:
cur = cur.next
cur.next = node
#指定位置添加节点(插入),此处设定: pos < 0 :将节点放置于链表头, pos > 0:将节点放置于链表尾
def insert(self,pos,item):
node = SingleNode(item)
if self.is_empty():
self._head = node
elif pos <= 0:
self.add(item)
else:
cur = self._head #游标
cur_pos = 0 # 此时游标所指位置
#找到链表中pos-1的位置,
while True:
if cur_pos == pos - 1:
#新节点指向此时位置后的节点
node.next = cur.next
cur.next = node
break
cur = cur.next
cur_pos+=1
#游标指向最后一位时,说明指定插入位置超过链表长度
if not cur.next:
cur.next = node
break
#删除链表中的所有指定节点
def remove(self,item):
cur = self._head
#当前cur的前一个节点
pre = None
while cur:
if cur.item == item:
#删除首个节点时
if not pre:
self._head = cur.next
else:
pre.next = cur.next
else:
pre = cur
# 后移一个节点
cur = cur.next
#判断一个节点是否存在
def search(self,item):
sur = self._head
while sur:
if sur.item == item:
return True
sur = sur.next
return False
if __name__ == '__main__':
single_link_list = SingleLL()
single_link_list.append('11')
single_link_list.append('22')
single_link_list.append('33')
single_link_list.append('44')
single_link_list.print_all()
print('----------')
single_link_list.insert(2,'21')
single_link_list.print_all()
print(single_link_list.search('21'))
print('-------')
single_link_list.remove('22')
single_link_list.print_all()
在实现这个链表时我想到了 python的赋值,深浅拷贝,python的垃圾回收机制
python的赋值,在上面对链表的操作中,都是用一个把 self._head 付给一个游标变量然后再依次把下一个节点赋值给 游标,在这里为什么对游标指向的结点进行更改而整个链表就会发生改变呢,下面解释:
这里先将一下 python对象主要分为两大类容器类型对象(list,dict,class..)和非容器类型对象(int,str..)。而像 a =[1],b=a 其实两个变量只是指向了同一块内存,这个时候id(a)==id(b)。其中一个变量发生改变时 a.append(2), 这个时候 打印 b 就是 [1,2] ,id(a)==id(b),代码如下:
a = [1]
b = a
print(id(a)==id(b))
a.append(2)
print(b)
print(id(a)==id(b))
#结果
True
[1, 2]
True
如果是非容器类对象可以发生的改变只有重新赋值 ,而赋值的根本意义是变量指向了另一块内存,如 a=2,b=a,id(a)==id(b), a重新赋值 a=3,这时 id(a)!=id(b),代码如下:
a = 2
b = a
print(id(a)==id(b))
print(b)
a = 3
print(id(a)==id(b))
#结果
True
2
False
在上面实现的链表中,SingleNode类实例化出来的对象也是一个容器类型对象。因此 节点进行改变,整个链表也发生改变。
python的垃圾回收机制,在上面链表操作中,我们所做的删除节点操作只是把这个节点的父节点指向了这个节点的子节点,
那么这个节点已经无用,在内存中占用着空间,此时就轮到垃圾回收机制大展身手了。
python的垃圾回收机制以引用计数为主,标记清除、分代回收为辅,
引用计数:如果一个对象的引用数为0,Python虚拟机就会回收这个对象的内存,在上文中删除一个节点,是将此节点的父节点指向此节点的子节点,此时,此节点已经没有被引用,引用数为0,内存被回收。因为 引用计数 存在一些缺陷(像两个容器类型对象循环调用)所以有有了两个作为辅助的回收机制,这里只是简单阐述一下,网上关于垃圾回收机制的优秀文章太多。