各种排序算法总结(Python,C++)

9 篇文章 0 订阅

快找工作了,该复习算法。这里总结一下排序算法。供以后查询

1、快排

当初研一的时候,老师留的实验作业就是写快速排序。其中pivot设为随机选择,与非随机选择。然后比较性能。

实际上做完实验,发现合理的pivot会导致 很平衡 的划分。我们需要故意设置一个有序的序列(对应快排最坏的情况),选择400000个int。性能还是差很多。将近10倍吧。

快排的思想 result = 【low】+pivot+【high】

然后对两个子区间【low】、【high】分别递归调用即可。
时间复杂度O(nlogn)。最好O(nlogn),最坏O(N2)。

空间复杂度:依情况而定,有的是原址排序,有的是非原址的,有的是递归调用,有的是循环实现。

【段子】当初黄老师问起时间复杂度:我们都说是O(nlogn)。他:“”错”。还有O(n2)的情况。遭到批评:“大学算法谁教的?!”当然:快排之所以叫快排,是因为:只要不是待排序的数组有序,那么一定能达到很好的性能,上课他又举例,还真是。而且nlogn它前面的系数很低。平均性能好像是1.44。
像nlogn的排序有好几个:堆排序,归并排序等。但是一般都弄不过快排。尤其是待排数组长度很大的时候。

def partition(seq):
    pivot,seq= seq[0],seq[1:]
    low=[x for x in seq if x<= pi]  #小于pivot放左边
    hi=[x for x in seq if x> pi]    #大于pivot放右边
    return low,pivot,hi

def quicksort(seq):
    if len(seq) <= 1:  #递归 base case
        return seq
    low,pivot,hi=partition(seq)  #进行一次划分
    return quicksort(low)+[pivot]+quicksort(hi) #递归划分

2、堆排序

谈到堆排序,我第一反应就是,有了快排干嘛用堆排序??!
实际 上解决大数据top-K的问题,他就派上了用场。

1-堆是一个完全二叉树,因此可以用连续内存表示。堆可分为:大根堆(堆顶元素最大),小根堆(堆顶元素最小)。
2-堆的表示:用数组(c),或者vector(c++)
数组的【】【2】【4】【3】【1】
3-这里空出第一个位置。就可以满足对于节点 i 他的父亲是 i/2。他的儿子 2i (左),2i+1 (右)。
4-建堆(n个元素)的时间为O(n)

堆排序过程(大根堆为例)

 1- 将待排序的序列构造成一个大顶堆 #此时堆顶为最大
 2- 将它移走(其实就是将它与堆数组的末尾元素交换,此时末尾元素就是最大值)。
 3- 此时,需要维护前n-1个元素堆的性质(堆调整)。第n个元素已经有序
 4- 调整完,此时又是一个n-1个元素的大根堆,再取堆顶与堆中最后一个元素交换。
 5- 此时,前需要维护数组前n-2个元素的堆性质(调整堆)。第n-1与第n个元素已经有序。 
 如此反复执行,便能得到一个有序序列了。

结论:大根堆,排序结果是升序,小根堆排序结果是降序
演示:http://www.benfrederickson.com/heap-visualization/

# 调整堆  
def adjust_heap(lists, i, size):  
    lchild = 2 * i + 1  
    rchild = 2 * i + 2  
    max = i  
    if i < size / 2:  
        if lchild < size and lists[lchild] > lists[max]:  
            max = lchild  
        if rchild < size and lists[rchild] > lists[max]:  
            max = rchild  
        if max != i:  
            lists[max], lists[i] = lists[i], lists[max]  
            adjust_heap(lists, max, size)  

# 创建堆  
def build_heap(lists, size):  
    for i in range(0, (size/2))[::-1]:  
        adjust_heap(lists, i, size)  

# 堆排序  
def heap_sort(lists):  
    size = len(lists)  
    build_heap(lists, size)  
    for i in range(0, size)[::-1]:  
        lists[0], lists[i] = lists[i], lists[0]  
        adjust_heap(lists, 0, i)  

那么开始提出 top-k 的问题如何做呢?
假设百度每天的热搜词有log文件。这个文件巨大,几十g(其中有相同的词)。找出某天top100。
先用hash_map,构建 < key=[词汇],value=[次数] > pair。构建之后我们需要对这个集合进行排序。先遍历前100个pair。构建最小堆。然后每次过来一个数就跟堆顶相比较,如果比堆顶大,则替换掉堆顶。进行一次堆调整。
这样我们发现:把数据存在磁盘上就可以比较。不用把待比较的元素都加载到内存中。

3、归并排序:

def merge(left, right):
  i, j = 0, 0
  result = []
  while i < len(left) and j < len(right):
    if left[i] <= right[j]:
      result.append(left[i])
      i += 1
    else:
      result.append(right[j])
      j += 1
  result += left[i:]
  result += right[j:]
  return result

def merge_sort(lists):
  # 归并排序
  if len(lists) <= 1:
    return lists
  num = len(lists) / 2
  left = merge_sort(lists[:num])
  right = merge_sort(lists[num:])
  return merge(left, right)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值