各种排序算法总结(Python,C++)
2017-06-15 10:12
267 查看
快找工作了,该复习算法。这里总结一下排序算法。供以后查询
实际上做完实验,发现合理的pivot会导致 很平衡 的划分。我们需要故意设置一个有序的序列(对应快排最坏的情况),选择400000个int。性能还是差很多。将近10倍吧。
快排的思想 result = 【low】+pivot+【high】
然后对两个子区间【low】、【high】分别递归调用即可。
时间复杂度O(nlogn)。最好O(nlogn),最坏O(N2)。
空间复杂度:依情况而定,有的是原址排序,有的是非原址的,有的是递归调用,有的是循环实现。
【段子】当初黄老师问起时间复杂度:我们都说是O(nlogn)。他:“”错”。还有O(n2)的情况。遭到批评:“大学算法谁教的?!”当然:快排之所以叫快排,是因为:只要不是待排序的数组有序,那么一定能达到很好的性能,上课他又举例,还真是。而且nlogn它前面的系数很低。平均性能好像是1.44。
像nlogn的排序有好几个:堆排序,归并排序等。但是一般都弄不过快排。尤其是待排数组长度很大的时候。
实际 上解决大数据top-K的问题,他就派上了用场。
1-堆是一个完全二叉树,因此可以用连续内存表示。堆可分为:大根堆(堆顶元素最大),小根堆(堆顶元素最小)。
2-堆的表示:用数组(c),或者vector(c++)
数组的【】【2】【4】【3】【1】
3-这里空出第一个位置。就可以满足对于节点 i 他的父亲是 i/2。他的儿子 2i (左),2i+1 (右)。
4-建堆(n个元素)的时间为O(n)
堆排序过程(大根堆为例)
结论:大根堆,排序结果是升序,小根堆排序结果是降序
演示:http://www.benfrederickson.com/heap-visualization/
那么开始提出 top-k 的问题如何做呢?
假设百度每天的热搜词有log文件。这个文件巨大,几十g(其中有相同的词)。找出某天top100。
先用hash_map,构建 < key=[词汇],value=[次数] > pair。构建之后我们需要对这个集合进行排序。先遍历前100个pair。构建最小堆。然后每次过来一个数就跟堆顶相比较,如果比堆顶大,则替换掉堆顶。进行一次堆调整。
这样我们发现:把数据存在磁盘上就可以比较。不用把待比较的元素都加载到内存中。
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)
相关文章推荐
- Python实现各种排序算法的代码示例总结
- 总结各种排序算法(C++)
- Python实现各种排序算法的代码示例总结
- 各种排序算法总结(C++实现)
- 各种排序算法分析总结
- c++调用python的总结
- 各种排序算法总结(待完成)
- C++ 的各种文件读写操作总结
- 各种排序算法的总结和比较
- 各种排序算法的总结和比较
- C/C++笔试面试题目汇总3——各种排序算法
- FORCAL与C/C++、MATLAB、Python、Lua等各种语言的速度比较
- 各种排序算法总结
- 数据结构各种排序算法总结
- 各种排序算法代码C++版
- 各种排序算法总结
- C++各种排序算法
- 各种排序算法的总结和比较
- 各种排序算法及其实现总结
- 各种排序算法分析总结