前言
继上篇 数据结构与算法之python归并排序 的数组的实现,这篇谈谈如何用一个链表实现。
选择链表
链表有单链表、双链表、循环链表,但是应该选择哪个呢?是的双链表是你的最佳选择。你可以试一下如果使用单链表的话即只有一个头指针或者尾指针 能否实现归并排序。来看下代码吧
双链表
class LinkNode(object):
"""
双链表,头指针删除节点,尾指针插入节点
"""
class Empty(Exception):
pass
class _Node:
__slots__ = '_element', '_next'
def __init__(self, element, next):
self._element = element
self._next = next
def __init__(self):
self._head = None # 头指针
self._tail = None # 尾指针
self._size = 0 # 链表长度
def __len__(self):
"""
链表长度
:return:
"""
return self._size
def is_empty(self):
"""
判断链表是否为空
:return:
"""
return self._size == 0
def add_node(self, data):
"""
增加节点, 尾插法
表长 +1
:return:
"""
new_node = self._Node(data, None)
if self.is_empty():
self._head = new_node # 如果是空链表,新插入的链表头指针也需要变更
else:
self._tail._next = new_node # 尾指针指向新的节点
self._tail = new_node # 尾指针后移
self._size += 1
def delete_node(self):
"""
删除节点: 头删除法
:return:
"""
if self.is_empty():
raise self.Empty('Link node is empty!')
_data = self._head._element
self._head = self._head._next
self._size -= 1
if self.is_empty():
self._tail = None
return _data
def first_data(self):
"""
首元素
:return:
"""
if self.is_empty():
raise self.Empty('link node is empty!')
return self._head._element
目前定义了双链表的结构,下面让我来看下归并排序的代码
归并排序
from functools import wraps
class MergeSortLinkNode(object):
def __init__(self, func):
wraps(func)(self)
def __merge(self, left: LinkNode, right: LinkNode, res: LinkNode):
"""
合并
:param left:
:param right:
:param res:
:return:
"""
while not left.is_empty() and not right.is_empty():
if left.first_data() < right.first_data():
res.add_node(left.delete_node())
else:
res.add_node(right.delete_node())
# 判断剩下的元素
while not left.is_empty():
res.add_node(left.delete_node())
while not right.is_empty():
res.add_node(right.delete_node())
def __merge_sort(self, sqlist: LinkNode):
"""
归并排序
:param sqlist: 待排序的链表
:return:
"""
link_node_length = len(sqlist) # 获取长度
if link_node_length < 2:
return
mid = link_node_length // 2
S1 = LinkNode()
S2 = LinkNode()
while len(S1) < mid:
S1.add_node(sqlist.delete_node())
while not sqlist.is_empty():
S2.add_node(sqlist.delete_node())
self.__merge_sort(S1)
self.__merge_sort(S2)
self.__merge(S1, S2, sqlist)
def __call__(self, *args, **kwargs):
res = self.__wrapped__(*args, **kwargs)
self.__merge_sort(res)
return res
这里我把归并排序定义为了一个类装饰器,想深入了解类装饰器的话,可以参考python3-cookbook 方面的信息
测试
import random
init_data = list() # 初始化结果
test_result = LinkNode() # 链表
print_res = list() # 打印排序后的结果
@MergeSortLinkNode
def example():
for i in range(10):
_elem = random.randint(1, 50)
init_data.append(_elem)
test_result.add_node(_elem)
return test_result
example()
while not test_result.is_empty():
print_res.append(test_result.delete_node())
print('....init_data: ', init_data)
print('....print_res: ', print_res)
这里随机生成了10的长度,执行下结果,因为是随机执行的所以每次执行的结果都不一样,我这里的结果如下:
如果你比较细心的话,可能已经发现再双链表的封装的特性是一个队列。其实任何一种形式的基本队列都可以很容易地作为归并排序算法的容器类型。