最近开始复习数据结构和算法,发现以前学过的知识遗忘了许多,得重新看看,写写代码。
单向链表
链表(link list)是一种非常基本的数据结构,与数组相比,链表的特点是内存是不连续的,前一个元素存储地址的下一个地址中存储的不一定是下一个元素。链表通过一个指向下一个元素地址的引用将链表中的元素串起来。
链表的基本单位是节点,节点包括一个值和一个指针:
节点类的实现十分简单:
class Node:
"""
节点类
"""
def __init__(self, value, next=None):
self.value = value
self.next = next
def get_data(self):
return self.value
def set_new_data(self, new_value):
self.value = new_value
有了节点类之后就可以实现链表类了,链表的一般操作有add(),insert(),find(),delete()等,时间复杂度均为O(n),都需要从头遍历链表。
链表类:
class LinkList(object):
"""
单向链表类
"""
def __init__(self, head=None):
self.head = head #初始化头点,是一个Node类
if not self.head:
self.length = 1
else:
self.length = 0
def get_head(self):
return self.head
def is_empty(self):
if not self.length:
return True
添加节点:
def append_node(self, data_or_node):
item = None
if isinstance(data_or_node, Node):
item = data_or_node
else:
item = Node(data_or_node)
if not self.head:
self.head = item
self.length += 1
else:
node = self.head #头节点始终保持不变
while node.next:
node = node.next
node.next = item
self.length += 1
#若头节点是指最近添加的节点
# self.head.next = item
# self.head = item
删除节点:
def delete_node(self, index):
if self.is_empty():
print("this link list is empty.")
return
if index<0 or index>=self.length:
print("error:out of index.")
return
if index == 0:
self.head = self.head.next
self.length -= 1
return
node = self.head
pre = self.head
while node.next and index:
pre = node
node = node.next
index -= 1
if not index:
pre.next = node.next
self.length -= 1
更新节点:
def update_node(self, index, value):
if self.is_empty() or index<0 or index>=self.length:
print("error:out of index.")
return
node = self.head
while node.next and index:
node = node.next
index -= 1
if not index:
node.value = value
查找节点:
def get_node(self, index):
if self.is_empty() or index<0 or index>=self.length:
print("error:out of index.")
return
node = self.head
while node.next and index:
node = node.next
index -= 1
if not index:
return node.value
def get_index(self, value):
if self.is_empty():
print("this link list is empty.")
return
node = self.head
j = 0
while node:
if node.value == value:
return j
else:
node = node.next
j += 1
if j == self.length:
print("%s not found" % str(value))
return
插入节点:(不好截图,就直接复制代码了)
插入节点的时候要注意从插入在头节点前的情况。
def insert_node(self, index, data_or_node):
if self.is_empty():
print("this link list is empty.")
return
if self.is_empty() or index<0 or index>=self.length:
print("error:out of index.")
return
item = None
if isinstance(data_or_node, Node):
item = data_or_node
else:
item = Node(data_or_node)
if index == 0:
item.next = self.head
self.head = item
self.length += 1
return
node = self.head
pre = self.head
while node.next and index:
pre = node
node = node.next
index -= 1
if not index:
pre.next = item
item.next = node
self.length += 1
清空链表:
def clear(self):
self.head = None
self.length = 0
源码如下:
class Node:
"""
节点类
"""
def __init__(self, value, next=None):
self.value = value
self.next = next
def get_data(self):
return self.value
def set_new_data(self, new_value):
self.value = new_value
class LinkList(object):
"""
单向链表类
"""
def __init__(self, head=None):
self.head = head #初始化头点,是一个Node类
if not self.head:
self.length = 1
else:
self.length = 0
def get_head(self):
return self.head
def is_empty(self):
if not self.length:
return True
def append_node(self, data_or_node):
item = None
if isinstance(data_or_node, Node):
item = data_or_node
else:
item = Node(data_or_node)
if not self.head:
self.head = item
self.length += 1
else:
node = self.head #头节点始终保持不变
while node.next:
node = node.next
node.next = item
self.length += 1
#若头节点是指最近添加的节点
# self.head.next = item
# self.head = item
def delete_node(self, index):
if self.is_empty():
print("this link list is empty.")
return
if index<0 or index>=self.length:
print("error:out of index.")
return
if index == 0:
self.head = self.head.next
self.length -= 1
return
node = self.head
pre = self.head
while node.next and index:
pre = node
node = node.next
index -= 1
if not index:
pre.next = node.next
self.length -= 1
def update_node(self, index, value):
if self.is_empty() or index<0 or index>=self.length:
print("error:out of index.")
return
node = self.head
while node.next and index:
node = node.next
index -= 1
if not index:
node.value = value
def get_node(self, index):
if self.is_empty() or index<0 or index>=self.length:
print("error:out of index.")
return
node = self.head
while node.next and index:
node = node.next
index -= 1
if not index:
return node.value
def get_index(self, value):
if self.is_empty():
print("this link list is empty.")
return
node = self.head
j = 0
while node:
if node.value == value:
return j
else:
node = node.next
j += 1
if j == self.length:
print("%s not found" % str(value))
return
def insert_node(self, index, data_or_node):
if self.is_empty():
print("this link list is empty.")
return
if self.is_empty() or index<0 or index>=self.length:
print("error:out of index.")
return
item = None
if isinstance(data_or_node, Node):
item = data_or_node
else:
item = Node(data_or_node)
if index == 0:
item.next = self.head
self.head = item
self.length += 1
return
node = self.head
pre = self.head
while node.next and index:
pre = node
node = node.next
index -= 1
if not index:
pre.next = item
item.next = node
self.length += 1
def clear(self):
self.head = None
self.length = 0
以上实现的是单向链表,除了单向链表之外还存在双向链表,循环链表等。
双向链表
双向链表就是有两个方向的链表。同单向链表不同,在双向链表中每一个节点不仅存储指向下一个节点的指针,而且存储指向前一个节点的指针。通过这种方式,能够通过在O(1)时间内通过目的节点直接找到前驱节点,但是同时会增加大量的指针存储空间。
双向链表与单向链表的实现大同小异,只不过是增加了前向指针。
class Node(object):
def __init__(self, value, p=None):
self.data = value
self.next = p
self.prev = p
# 如果加入尾节点tail,代码会更简单
class LinkList(object):
def __init__(self, head=None):
self.head = head
if not head:
self.length = 1
else:
self.length = 0
def is_empty(self):
if not self.length:
return True
def append(self, data_or_node):
item = None
if isinstance(data_or_node, Node):
item = data_or_node
else:
item = Node(data_or_node)
if not self.head:
self.head = item
self.length += 1
else:
node = self.head
while node.next:
node = node.next
node.next = item
node.prev = node
self.length += 1
def insert(self, index, data_or_node):
if self.is_empty():
print("this link list is empty.")
return
if self.is_empty() or index < 0 or index >= self.length:
print("error:out of index.")
return
item = None
if isinstance(data_or_node, Node):
item = data_or_node
else:
item = Node(data_or_node)
if index == 0:
item.next = self.head
self.head = item
self.length += 1
return
if index == 0:
item.next = self.head
self.head.prev = item
self.head = item
self.length += 1
return
node = self.head
while node.next and index:
node = node.next
index -= 1
if not index:
pre_node = node.pre
pre_node.next = item
item.prev = pre_node
item.next = node
node.prev = item
self.length += 1
循环链表(Circular Linked list)
循环链表与双向链表相似,不同的地方在于:在链表的尾部增加一个指向头结点的指针,头结点也增加一个指向尾节点的指针,以及第一个节点指向头节点的指针,从而更方便索引链表元素。
关于链表的面试题比较多样化,常见的有:
1、单链表的创建和遍历
2、求单链表中节点的个数
3、查找单链表中的倒数第k个结点(剑指offer,题15)
4、查找单链表中的中间结点
5、合并两个有序的单链表,合并之后的链表依然有序【出现频率高】(剑指offer,题17)
6、单链表的反转【出现频率最高】(剑指offer,题16)
class ReverseLinkList:
"""
反转链表
"""
def __init__(self, linklist, head):
self.linklist = linklist
self.head = head
def reverse_linklist(self):
if not self.linklist or self.linklist.next is None:
return self.linklist
node = self.head.next
self.head.next = None
pre_node = self.head
while not node:
next_node = node.next
node.next = pre_node
pre_node = node
node = next_node
return pre_node
7、从尾到头打印单链表(剑指offer,题5)
8、判断单链表是否有环
9、取出有环链表中,环的长度
10、单链表中,取出环的起始点(剑指offer,题56)。本题需利用上面的第8题和第9题。
11、判断两个单链表相交的第一个交点(剑指offer,题37)