链表是其余链式结构的基础,一般来说链表搞懂了后面的栈和队列(只是链表加了些限定规则)也就懂了。再往后的二叉搜索树除了删除结点比较复杂之外其实其他操作(增改查)和链表的增改查都差不多。
早先用 C 写过很多次链表,用 Java 也写过几次,转到 Python 就没思路了。其实套路都一样。
// 结点,存数据域和前后指针
typedef struct _NODE{
int item;
struct _NODE *next;
struct _NODE *prev;
}NODE, *PNODE;
// 链表,存头尾结点和其他信息
typedef struct _LIST{
PNODE head;
PNODE tail;
int size;
}LIST, *PLIST;
上面是 C 中定义链表的写法,结构体的命名参考了 WIN32 的写法。
可以看到我们分别定义了两个结构体用来存储结点信息和链表信息,换到 OOP 就是将这两个结构体定义为一个两个类。
下面上 Python 代码:
'''
双链表部分 Python 实现
2020年5月28日13:47:22
C 里面的链表都已经刻在 DNA 里了,用 Python 还没有思路,其实套路都一样
定义一个节点域和链表即可'''
class Node(object):
def __init__(self, value=None, next=None, prev=None):
'''结点和数据域'''
self.value = value
self.next = next
self.prev = prev
def get_value(self):
return self.value
def get_next(self):
return self.next
def __str__(self):
return f'NodeValue {self.value}'
class LinkedList(object):
def __init__(self, value=None):
'''链表类'''
self.tail = self.head = Node(value)
self.length = 1
def append(self, value):
node = Node(value, prev=self.tail)
self.tail.next = node
self.tail = node
def pre_append(self, value):
node = Node(value, self.head)
self.head.prev = node
self.head = node
def get_length(self):
return self.length
def traverse(self, func):
'''使用指定函数遍历链表'''
head = self.head
while head:
func(head)
head = head.next
def re_traverse(self, func):
'''反向遍历链表'''
tail = self.tail
while tail:
func(tail)
tail = tail.prev
def reverse(self):
'''反转链表还是不熟,双链表的反转其实和单链表反转同理'''
prev, curr, next = None, self.head, self.head
while next:
next = next.next
curr.prev = curr.next
curr.next = prev
prev = curr
curr = next
self.tail = self.head
self.head = prev
def prt_value(node):
print(node.value)
def main():
li = LinkedList(-1)
for i in range(10):
li.append(i)
li.reverse()
li.append(100)
li.pre_append(1010)
li.traverse(prt_value)
print('*' * 10)
li.re_traverse(prt_value)
# li.traverse(prt_value)
if __name__ == '__main__':
main()
这段代码只实现了头插法和尾插法新增元素,删改查这三个操作都基于查,熟悉链表的话很容易实现。
另外 Python 不用考虑内存泄漏的问题,所以可以更加专注于实现。
唯一值得参考的是reverse
这个方法,该方法实现了反转双链表的算法。