heapSort1和heapSort2的不同

来源:4-5 基础堆排序和Heapify

小叶柏杉

2016-12-17

我认为heapSort1比heapSort2慢的原因,是因多了一个maxheap.insert函数,但是insert中存在一个向上排序(shiftUp函数),在插入完成后,也就意味着已经排序,成为最小堆,再进行一次最大堆的排序。

要是在insert函数中,取消‘’shiftUp(count+1)‘’,直接插入一个无序的,直接用shiftDown排序。

与heapSort2算法的效率的差异,是否存在此处?

void insert(Item item){
        assert( count + 1 <= capacity );
        data[count+1] = item;
        //shiftUp(count+1);
        count ++;
    }

4-5 基础堆排序和Heapify 中的疑问。请老师解答一下 @liuyubobobo

写回答

2回答

liuyubobobo

2016-12-18

我们可以看到heapSort1的代码:

template<typename T>    
void heapSort1(T arr[], int n){
    // 创建最大堆    
    MaxHeap<T> maxheap = MaxHeap<T>(n);    
    for( int i = 0 ; i < n ; i ++ )    
        maxheap.insert(arr[i]);    
    
    // 逐渐取出最大元素
    for( int i = n-1 ; i >= 0 ; i-- )    
        arr[i] = maxheap.extractMax();    
}


和heapSort2的代码:

template<typename T>    
void heapSort2(T arr[], int n){  
    // 创建最大堆  
    MaxHeap<T> maxheap = MaxHeap<T>(arr,n);    
    
    // 逐渐取出最大元素
    for( int i = n-1 ; i >= 0 ; i-- )    
        arr[i] = maxheap.extractMax();    
}

 

后面一部分是相同的,都使用了这样的循环:

for( int i = n-1 ; i >= 0 ; i-- )    
    arr[i] = maxheap.extractMax();


在这个循环中,我们不断利用maxheap的性质取出最大的元素,完成了对整个数组的排序。所以,两种方法不同的地方在于是如何创建的最大堆。如果你将insert中的shiftUp操作删除,则第一种算法的第一部分无法创建一个最大堆。第二部分的操作就是错误的。我没有特别理解你说的“直接用shiftDown排序”是什么意思。事实上,heapSort2的MaxHeap<T>(arr,n); 就隐含了ShiftDown操作。我们在4-6介绍的原地堆排序,原理和heapSort2类似,也是不断的使用shiftDown完成堆排序。如果你说的是这个意思,恭喜你,你直接找到了一个更优的解决方案:)


在这里,我主要想向大家介绍的一个有意思的事实是,heapSort1和heapSort2中两种创建堆的方式,他们的复杂度是不一样的。heapSort1中逐渐将元素插入到堆中的方式,其时间复杂度是O(nlogn)的;但是heapSort2中反向从第一个非叶子节点倒序不断ShiftDown的过程,最终也创建了一个堆,但是其时间复杂度是O(n)的。这背后的数学推倒比较复杂,在课程中我只提了一嘴,使用实验的方式向大家展示了这个区别。有兴趣的同学,可以查阅更多资料学习一下:) 

2
1
小叶柏杉
非常感谢!
2016-12-20
共1条回复

Penguinbupt

2017-04-23

你说的直接插入insert无序的,然后在shiftDown。

这就是第二种排序方式嘛,第二种方式是直接给一个无序的数组,从n/2至1进行shiftDown操作进行建堆。

0
0

算法与数据结构(C++版) 面试/评级的算法复习技能包

课程专为:短时间内应对面试、升职测评等艰巨任务打造

11187 学习 · 1614 问题

查看课程