【数据结构】排序笔记

一. 练手:冒泡排序

为什么选冒泡排序写呢?

因为之前没注意到:只要有一次冒泡发现数组没有进行交换操作,则代表数组已有序,不用再排了。

#include
#include
using namespace std;
void bubbleSort(int *s,int l){
    int flag=0;
    for(int i=0;i

但是请注意,基础的三种排序,时间效率都是O(N^2),我们希望通过让数组实现部分有序的方法减少整体交换次数。

二. 堆排序

根本目的:减少交换的次数,从而提高排序效率。

1. 先变为大顶堆

大顶堆就是确保每棵树的树根都比它的两个儿子大,至于左儿子右儿子的大小关系就不是大顶堆现在需要考虑的问题。从而使得当正式排序的时候,每次删除的堆顶都是这个树中最大的元素。

实现方法就是堆中的insert(),这里说一下思路。

对于一棵完全二叉树,最后一个非叶子结点的下标是l/2-1,l是数组长度。

如果一个非叶子结点小于它左右儿子中任何一个,则将最大的儿子换成该结点,该结点替换到它儿子的位置上去。但是替换之后这个儿子树的结构也改变了,于是继续判断儿子树的根结点和儿子树的叶子结点的大小,直到不需要替换或者轮到了能轮的最后一个非叶子结点为止。

2. 堆顶依次出堆

所以我们可以确定,堆顶一定是这个堆中最大的值。

之前对于堆中删除堆顶的操作就是惰性删除,将堆顶和底部替换,修改长度,然后将当前的暂时堆顶(原最后一个元素)和儿子进行比较,重复之前变为大顶堆的操作。

要注意的是这里长度变了。

另外我偷了一个懒,整个moveon函数都应该需要判断右儿子是否是空的,这里简单置为零。

#include
#include
using namespace std;
void moveon(vector&N,int i,int h){//非叶子结点,比较两个儿子的大小,然后比较大儿子和它的大小,大儿子大就和它交换
    while(i<=h)
    {    
        int left_son=(i+1)*2-1;
        int right_son=(i+1)*2;
        int tempi;
        if(max(N[right_son],N[left_son])>N[i])
        {
            int tempnum=N[i];
            N[i]=max(N[right_son],N[left_son]);
            if(N[right_son]>N[left_son]){
                tempi=right_son;
                N[right_son]=tempnum;
            }
            else{
                tempi=left_son;
                N[left_son]=tempnum;
            }   
            i=tempi;
        }
        else{
            return ;
        }
    }
}
void heapSort(vector&N ){
    int l=N.size();
    for(int i=l/2-1;i>=0;i--){//所有的非叶子结点都在这里了
        moveon(N,i,l/2-1);
    }
    vectortempN;
    for(int i=l-1;i>=0;i--){//交换,给新结点找位置。
        tempN.push_back(N[0]);
        N[0]=N[i];
        N[i]=0;
        moveon(N,0,(i+1)/2-1);
    }
    for(int i=l-1;i>=0;i--){
        N[l-i-1]=tempN[i];
    }
}
int main(){
    int tempnums[5]={4,6,3,5,9};
    vectornums(tempnums,tempnums+5);
    heapSort(nums);
    for(int i=0;i<5;i++){
        cout<

你可能感兴趣的:(重学数据结构笔记,c++,算法,数据结构)