您的位置:首页 > 编程语言 > C语言/C++

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

2017-06-15 10:12 267 查看
快找工作了,该复习算法。这里总结一下排序算法。供以后查询

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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: