1.首先我们要清楚python中不同的一点,python中的变量不是数据存储地址的别名,而是一个指向数据存储地址的指针,所以为什么python中没有指针,就是因为变量本身就是指针。例如python中的交换变量。
a = 1
b = 99
print(a,b)
a,b = b,a
print(a, b)
返回值:
F:\测试>python -u "f:\测试\测试文档.py"
1 99
99 1
2.然后就是链表,链表由节点组成,节点由一个数据区和一个指针组成,就像一串手链一样,节点之间依次用指针连接起来,所以我们为了创建链表,要先创建一个能够生成节点的类。
class Node:
'''定义节点类,用来获取新节点'''
def __init__(self,elem):
self.elem = elem
self.next = None
我们观察这个类,里面由我们上面提到的两个元素,即数据区(self.elem)和指针(self.next)。有了节点类后我们就可以创建链表类了。
class singlelinklist:
def __init__(self):
self.__head = None #定义一个头指针,用来取第一个节点
在初始化里,我们引入一个头指针self.__head,并且定义成私有变量 ,这样可以才取到第一个节点。有了这两个类,我们就有了链表的外框。然后我们就需要在链表类内部定义方法,包括判定为空,查看链表长度,遍历链表以及增 删 改 查。
3.首先是判定是否为空,判定是否为空,我们不需要额外输入参数,直接返回bool值即可。
def is_empty(self):
'''判断是否为空'''
return self.__head == None #直接返回头指针的内容即可
return后面的式子即判断头指针指向的内容,如果为空,说明一个节点都没有,即为空。
4.查看链表长度
def length(self):
'''输出链表的节点数,即链表长度'''
cur = self.__head #定义一个自由指针
count = 0 #计数
while cur != None: #该终止条件,让cur可以停在链表尾指向的 None
cur = cur.next #往后移动一次自由指针
count += 1
return count #遍历结束后,返回计数值
查看链表长度,我们则需要遍历链表,所以要引入一个自由指针(cur),cur要先指向第一个节点,即通过头指针指向第一个节点。然后再用count来计数,cur前进一步(即把cur.next赋给cur),计数加一,最后遍历结束指向None时,count即为链表总节点数,返回计数值即可。注意,while的停止条件为关键,可以控制cur最后指向的位置。
原理图
5.遍历链表
def travel(self):
'''遍历并打印链表'''
cur = self.__head
while cur != None:
print(cur.elem,end=' ')
cur = cur.next
遍历链表和上面测量链表长度的循环原理一样,循环时把每个节点的数据区打印出来。
6.头插法
def add(self,elem):
'''头插法'''
node = Node(elem) #获取一个新节点,存入我们输入的元素
node.next = self.__head #让新节点的指针指向第一个节点
self.__head = node #让头节点指向新节点
头插法,就是在头指针(__head)和头结点(node)之间插入一个新节点,所以我们先用node实例化Node类,让其成为一个节点对象,然后先让新节点指向之前的头结点,不打乱原链表的结构,再让头指针指向新节点。
原理图:
7.尾插法
def append(self,elem):
'''尾插法'''
node = Node(elem)
cur = self.__head
if self.is_empty(): #如果链表为空
self.__head = node #则让头指针指向新节点
else:
while cur.next != None: #该终止条件,可以让cur停在最后一个节点上
cur = cur.next
cur.next = node #让尾节点指针指向新节点
尾插法和头插法不同的点在于我们需要遍历一次链表,才可以找到尾节点,所以我们需要用到一个自由指针来在链表内循环,那么循环终止的条件是什么?就是要让自由指针最后指向尾节点。我们想出基本思路后,就要考虑极限问题,如果链表为空,那么就要用头指针来指向新节点,所以我们还需要用到条件语句。
原理图:
8.按索引插入节点
def insert(self,index,elem):
'''在索引前面插入节点'''
node = Node(elem)
count = 0
cur = self.__head
if index < 0: #如果输入的索引小于零,则为头插法
self.add(elem)
elif index > (self.length() - 1): #输入的索引大于链表最大索引,则为尾插法
self.append(elem)
else:
while count < index-1: #让cur停在索引节点的前一个节点上
count += 1
cur = cur.next
node.next = cur.next #遍历结束后,先让新节点指针指向我们输入的索引节点,再让cur指针指向新节点
cur.next = node
1.基本思路:我们需要找到索引位置,所以用到自由指针来遍历链表,且需要一个计数君,来帮助我们判断自由指针移动了几次,移动结束后,应该让自由指针指向索引位置的前一个节点,所以while的终止条件很重要!然后我们需要考虑极限情况,如果我们输入的index小于零,那我们就按照头插法处理,如果index大于链表最大,就按照尾插法处理
2.原理图:注意应该先完成node的指针操作,不破坏原链表的结构的情况下,悄悄的改变链表中的指针。
9.删除元素
def remove(self,elem):
'''删除输入的元素'''
pre = None #再引入一个指针,用来指向cur的前一个节点,我们称之为 前指针
cur = self.__head
while cur != None:
if cur.elem == elem: #判断cur指向节点的元素是否等于我们输入的元素
if cur == self.__head: #再判断cur是否为头节点
self.__head = cur.next #让头指针指向cur的下一个节点
else:
pre.next = cur.next #不是头节点,则让前指针指向节点的指针指向cur指向节点指向的下一个节点
break
else:
pre = cur #如果不是我们输入的元素,则让前指针移动至cur位置,再让cur后移一位
cur = cur.next
1.删除节点,即让被删除节点的前一个节点的指针指向被删除节点的下一个节点,从而被删除节点就不存在于链表中了,那么我们需要两个指针,一个(cur)用来指向被删除节点,一个(pre)用来指向前一个节点,遍历链表时,让两个指针一前一后的移动,pre始终应该指向cur指向节点的前一个节点。当我们遍历到需要删除的节点时,我们要先判断节点内数据区是否为我们输入的elem,如果是,就用pre和cur两个指针来删除该节点。
2.考虑极限情况:如果删除的是头结点,我们则需要改变头指针(head)的指向,就不是改变pre指针的指向了。 尾节点的话,我们依然可以用pre和cur指针来完成删除操作。
3.原理图:
10.搜查元素是否存在
def search(self,elem):
'''搜查该元素是否存在链表中'''
cur = self.__head
while cur != None:
if cur.elem == elem: #遍历链表时,若遍历到我们输入的元素,则返回bool值:True
return True
else:
cur = cur.next
return False #遍历结束没有找到就返回bool值:False
定义一个自由指针cur,然后遍历列表,并且用条件语句来判断节点内的数据区是否为我们输入的元素,遍历到了就返回True,遍历结束后如果都没有返回值就说明链表中没有我们输入的元素,就返回False
10.总代码
class Node:
'''定义节点类,用来获取新节点'''
def __init__(self,elem):
self.elem = elem
self.next = None
class singlelinklist:
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: #该终止条件,让cur可以停在链表尾指向的 None
cur = cur.next #往后移动一次自由指针
count += 1
return count #遍历结束后,返回计数值
def travel(self):
'''遍历并打印链表'''
cur = self.__head
while cur != None:
print(cur.elem,end=' ')
cur = cur.next
def add(self,elem):
'''头插法'''
node = Node(elem) #获取一个新节点,存入我们输入的元素
node.next = self.__head #让新节点的指针指向第一个节点
self.__head = node #让头节点指向新节点
def append(self,elem):
'''尾插法'''
node = Node(elem)
cur = self.__head
if self.is_empty(): #如果链表为空
self.__head = node #则让头指针指向新节点
else:
while cur.next != None: #该终止条件,可以让cur停在最后一个节点上
cur = cur.next
cur.next = node #让尾节点指针指向新节点
def insert(self,index,elem):
'''在索引前面插入节点'''
node = Node(elem)
count = 0
cur = self.__head
if index < 0: #如果输入的索引小于零,则为头插法
self.add(elem)
elif index > (self.length() - 1): #输入的索引大于链表最大索引,则为尾插法
self.append(elem)
else:
while count < index-1: #让cur停在索引节点的前一个节点上
count += 1
cur = cur.next
node.next = cur.next #遍历结束后,先让新节点指针指向我们输入的索引节点,再让cur指针指向新节点
cur.next = node
def remove(self,elem):
'''删除输入的元素'''
pre = None #再引入一个指针,用来指向cur的前一个节点,我们称之为 前指针
cur = self.__head
while cur != None:
if cur.elem == elem: #判断cur指向节点的元素是否等于我们输入的元素
if cur == self.__head: #再判断cur是否为头节点
self.__head = cur.next #让头指针指向cur的下一个节点
else:
pre.next = cur.next #不是头节点,则让前指针指向节点的指针指向cur指向节点指向的下一个节点
break
else:
pre = cur #如果不是我们输入的元素,则让前指针移动至cur位置,再让cur后移一位
cur = cur.next
def search(self,elem):
'''搜查该元素是否存在链表中'''
cur = self.__head
while cur != None:
if cur.elem == elem: #遍历链表时,若遍历到我们输入的元素,则返回bool值:True
return True
else:
cur = cur.next
return False #遍历结束没有找到就返回bool值:False
测试代码:
l1 = singlelinklist() #用l1实例化链表类
print(l1.is_empty()) #打印是否为空
print(l1.length()) #打印列表长度
l1.append(1) #尾插法插入一个1
print(l1.is_empty())
print(l1.length())
l1.append(3) #尾插一个3
l1.add(100) #头插法插入一个100
print(l1.travel())
l1.insert(1,4) #在索引为1的节点前面加入一个元素4
print(l1.travel()) #遍历链表
print(l1.search(3),l1.search(99)) #搜查3和99是否存在于链表中
l1.remove(100) #除去元素100
print(l1.travel()) #遍历链表
返回值:
F:\测试>python -u "f:\测试\链表.py"
True
0
False
1
100 1 3 None
100 4 1 3 None
True False
4 1 3 None
说明功能都能正常运行(以上为自己的一些总结,欢迎大家一起讨论)