数组和链表中的归并排序/堆排序

题目

  1. 有一个数组,对其进行 O ( n log ⁡ n ) O(n\log n) O(nlogn)时间复杂度的归并排序
  2. 有一个链表,对其进行 O ( n log ⁡ n ) O(n\log n) O(nlogn)时间复杂度的归并排序
  3. 对链表的二路归并部分使用堆排序实现
1.归并排序的思路
  • 递归基:数组或链表中的元素个数小于2,不用排序,返回数组
  • 二分:找到数组或链表的中点,继而分为前后两部分
  • 二分递归:对前后两部分数组或链表分别进行递归处理得到lara
  • 二路归并:对二路递归得到的lara的元素进行归并处理
2.数组的归并排序

按照归并排序的思路,默写下数组归并排序的过程:

def mergesort(nums:"List")->"List":
	#递归基
	if len(nums)<2: return nums
	#二分
	mid = len(nums)//2
	#二分递归
	la = mergesort(nums[:mid])
	ra = mergesort(nums[mid:])
	#二路归并
	res = []
	i = j = 0
	while i<len(la) or j<len(ra):
		if i<len(la) and (j>=len(ra) or la[i]<=ra[j]):
			res.append(la[i])
			i += 1
		if j<len(ra) and (i>=len(la) or ra[j]<la[i]):
			res.append(ra[j])
			j += 1
	return res
if __name__ == "__main__":
	nums = [1,5,1,2,3,0,-5]
	print(mergesort(nums))#[-5,0,1,1,2,3,5]
3.链表的归并排序

首先简单定义单向链表:

class ListNode:
	def __init__(self,x):
		self.val = x
		self.next = None

同样的,依据归并排序的思想,我们分为以下几个步骤进行讲述:

3.1递归基

我们知道归并排序的递归基是当数组/链表中的元素小于2个时,返回数组/链表。假设链表的头节点为head,由此我们得到链表递归排序的递归基为:

if not head or not head.next: return head
3.2二分

我们对于数组的二分可以直接使用mid = len(nums)//2实现;但对于链表,我们可以通过设置快慢指针,(lower = head, faster = head.next)使得快指针的速度是慢指针的两倍,这样当快指针指到末尾时,慢指针就找到链表的中间节点(前半部分的最后一个节点):

lower, faster = head, head.next
while lower and faster and faster.next:
	lower = lower.next
	faster = faster.next.next
mid = lower.next
lower.next = None

这里我们使用while lower and faster and faster.next:,保证了lowernext属性,fasternext属性,以及faster.nextnext属性.

3.3.二分递归

和数组的二分递归一样,我们对前后两部分分别进行二路递归:

la = self.sortList(head)
ra = self.sortList(mid)
3.4二路归并

我们可以分为共同长度部分多出来的部分
我们可以写出具有dummy头节点的二路归并如下:

dummy = ListNode(None)
cur = dummy
#处理共同长度部分
while la and ra:
	if la.val <= ra,val:
		cur.next = la
		la = la.next
	else:
		cur.next = ra
		ra = ra.next
	cur = cur.next
#处理多出来的部分
cur.next = la if la else ra
3.5返回值

返回dummy节点的下一个节点

return dummy.next 

得到完整代码如下:

$code for ListSort:
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        #递归基
        if not head or not head.next: return head
        #二分
        lower, faster = head, head.next
        while lower and faster and faster.next:
            lower = lower.next
            faster = faster.next.next
        mid = lower.next
        lower.next = None
        #二分递归
        la = self.sortList(head)
        ra = self.sortList(mid)
        #二路归并(带dummy头节点)
        dummy = ListNode(None)
        cur = dummy
        while la and ra:
            if la.val < ra.val:
                cur.next = la 
                la = la.next 
            else:
                cur.next = ra 
                ra = ra.next
            cur = cur.next 
        cur.next = la if la else ra 
        return dummy.next
4.二路归并部分使用二叉堆

  我们可以使用小顶堆实现二路归并部分,我们注意到这化简为一个堆排序的问题,通过不断地入堆、出堆处理,我们得到最终的结果。
  假设我们已经得到要二路归并的前后两个链表lara,我们导入heapq:

import heapq

为兼容起见,注意在应用heapq时不要压入自定义的类。
我们得到二路归并的部分:

lists = [la, ra]
heap = []
dummy = ListNode(None)
cur = dummy
#初始化优先队列
for i in range(len(lists)):
	if lists[i]:
		heapq.heappush(heap,(lists[i].val,i))
		lists[i] = lists[i].next
#堆排序
while heap:
	val, idx = heapq.heappop(heap)
	cur.next = ListNode(val)
	cur = cur.next
	if lists[i]:
		heapq.heappush((lists[i].val, i))
		lists[i] = lists[i].next
return dummy.next
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
各种数据结构的排序算法适用于不同的排序需求。以下是一些常见的数据结构和对应的排序算法: 1. 数组(Array): 数组是最常见的数据结构之一,适用于大多数排序算法。例如,插入排序、选择排序、冒泡排序和快速排序等算法都可以用于对数组进行排序。 2. 链表(Linked List): 链表是另一种常见的数据结构,由节点组成,每个节点包含一个元素和指向下一个节点的指针。对链表进行排序的常用算法有插入排序和归并排序。 3. 栈(Stack)和队列(Queue): 栈和队列是特殊的线性数据结构,栈是后进先出(LIFO),队列是先进先出(FIFO)。对于栈和队列,一般不需要进行排序。 4. 堆(Heap): 堆是一种二叉树结构,具有特定的性质,例如最大堆或最小堆。对堆进行排序的算法有堆排序。 5. 树(Tree): 树是一种非线性的数据结构,包括二叉树、平衡二叉树、红黑树等。对树进行排序的算法有二叉树排序、AVL树排序等。 6. 图(Graph): 图是一种由节点和边组成的数据结构,适用于某些特定的排序算法,例如拓扑排序。 总结来说,各种数据结构可以使用不同的排序算法进行排序,选择适当的排序算法取决于数据结构的特点和排序需求。<span class="em">1</span> #### 引用[.reference_title] - *1* [数据排序MapReduce实例](https://download.csdn.net/download/qq_37647812/88251299)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值