AKever

导航

算法 -- 堆排序

算法(堆排序)

这里的堆是指二叉堆, 二叉堆就是一种满足堆的两个特性的一颗完全二叉树,也叫优先队列。(区别于内存的堆。)

理解链接:http://www.cnblogs.com/zabery/archive/2011/07/26/2117103.html

时间复杂度

 O(n*log(n)),

其他堆:

二叉堆
二项堆
斐波那契堆

对类型: 最小堆最大堆

原理:

1. 现在数组是一个堆的形式:如下图(7个)
2. 循环n次(即从7开始倒循环),每次循环都会在根上得到最值,把最值与数组尾交换(1与7交换)
3. 2步骤中的循环一次循环m/2次(7/2),循环之后再根上得到最值
4. 2步骤循环结束就排序完毕了

for(m=n;n>0;n--) {
    for(i=m/2;i>0;i--)
}

操作:插入,删除,排序

warn:

模板中类的函数声明与定义需都写在同一文件下
下面实现中,插入删除操作影响类的对象数据(如:mHeap),不影响传入的数组(如:arr)。
排序造作指影响传入的数据(如:arr)

 

以下是代码实现

#pragma once
/**
 * 二叉堆
 *
 * @author skywang
 * @date 2014/03/07
 */
#include <iomanip>
#include <iostream>
using namespace std;

template <class T>
class HeapSort{
private:
    /*
     * 当插入或删除数据时,数组长度产生变化,创建容器数组辅助实现 (mHeap)
     */
    T *mHeap;         // 数据
    int mCapacity;    // 数组容量(总)
    int mSize;        // 实际容量
private:
    // 建堆(将最值置顶) = (n/2)次(sortAdjust)
    void BuildHeap(T arr[], int len, bool bDesc);
    void sortAdjust(T arr[], int len, int cur, bool bDesc);
public:
    // 构造函数
    HeapSort();
    HeapSort(int capacity);
    ~HeapSort();

    // 直接数组进行排序(排序的数组, 数组长度, 是否倒排序)
    int filtersort(T arr[], int len, bool bDesc);
    // 直接返回data在二叉堆中的索引
    int getIndex(T arr[], int len, T data);

    // 删除最大堆中的data(吃操作将影响成员数据)
    int remove(T arr[], int len, T data, bool bDesc);
    // 将data插入到二叉堆中(吃操作将影响成员数据)
    int insert(T arr[], int len, T data, bool bDesc);
    // 删除插入后,数据存储在成员变量中,提供函数供外部调用
    T* getHeap();
    int getSize();
    
    //(默认输出mHeap)打印数组
    void print();
    void print(T arr[], int len);
};

/* 
 * *********************************************************
 * 构造函数
 * *********************************************************
 */
template <class T>
HeapSort<T>::HeapSort()
{
    new (this)HeapSort(30);
}
/*
 * 带参构造函数
 */
template <class T>
HeapSort<T>::HeapSort(int capacity)
{
    mSize = 0;
    mCapacity = capacity;
    mHeap = new T[mCapacity];
}
/* 
 * 析构函数
 */
template <class T>
HeapSort<T>::~HeapSort() 
{
    msize = 0;
    mcapacity = 0;
    delete[] mHeap;
}

/*
 **********************************************************
 * 堆排序 start
 **********************************************************
 */
template <class T>
void HeapSort<T>::BuildHeap(T arr[], int len, bool bDesc)
{
     int i;
     int begin = len/2;  //最后一个非叶子节点
     for (i = begin; i >= 0; i--)
     {
         this->sortAdjust(arr, len, i, bDesc);  
     }
}

template <class T>
void HeapSort<T>::sortAdjust(T arr[], int len, int cur, bool bDesc)
{
    int left = cur*2;
    int right = cur*2+1;
    int parent = cur;
    int size = len;
    int temp;
    if(bDesc)
    {
        if(left < size && arr[parent] > arr[left])
            parent = left;
        if(right < size && arr[parent] > arr[right])
            parent = right;
    }
    else 
    {
        if(left < size && arr[parent] < arr[left])
            parent = left;
        if(right < size && arr[parent] < arr[right])
            parent = right;
    }
    if(cur != parent)
    {
        //交换父节点和和拥有最大值的子节点交换
        temp = arr[parent];
        arr[parent] = arr[cur];
        arr[cur] = temp;
    } 
}

/* 
 * 需要排序的数组 返回值:
 *     0,表示成功
 *    -1,表示失败
 */
template <class T>
int HeapSort<T>::filtersort(T arr[], int len, bool bDesc)
{
    int t_len = len;
    int temp;
    
    while (t_len>0)
    {
        
        this->BuildHeap(arr, t_len, bDesc);
        temp = arr[t_len-1];
        arr[t_len-1] = arr[0];
        arr[0] = temp;
        t_len --;
    }
    return 0;
}

/****** 堆排序 end *******************************************

/*
 * 删除最大堆中的data, 数组长度改变,依赖类成员数据操作
 * 插入后排序的数据存储在该对象成员变量内(mHeap, mCapacity, mSize), 同时不影响传入的数组数据
 */
template <class T>
int HeapSort<T>::remove(T arr[], int len, T data, bool bDesc)
{
    int index;
    // 如果"堆"已空,则返回-1
    if(len == 0)
        return -1;

    // 获取data在数组中的索引
    index = getIndex(arr, len, data); 
    if (index==-1)
        return -1;

    //将数据存储到该对象中
    if(mCapacity<len)
    {
        mCapacity = len;
        delete[] mHeap;
        mHeap = new T[mCapacity];
    }
    this->mSize = len;
    for(int i=0;i<mSize;i++)
        mHeap[i] = arr[i];

    mHeap[index] = mHeap[--mSize];    // 用最后元素填补
    this->filtersort(mHeap, mSize, bDesc);

    return index;
}

/* 
 * 将data插入到二叉堆中
 * 插入后排序的数据存储在该对象成员变量内(mHeap, mCapacity, mSize),同时不影响传入的数组数据
 */
template <class T>
int HeapSort<T>::insert(T arr[], int len, T data, bool bDesc)
{
    //将数据存储到该对象中
    if(mCapacity<len+1)
    {
        mCapacity = len+1;
        delete[] mHeap;
        mHeap = new T[mCapacity];
    }
    this->mSize = len;
    for(int i=0;i<mSize;i++)
    {
        mHeap[i] = arr[i];
    }

    // 如果"堆"已满,则返回
    if(mSize == mCapacity)
        return -1;
    mSize++;  
    mHeap[mSize-1] = data;        // 将"数组"插在表尾

    //排序并获取 index
    this->filtersort(mHeap, mSize, bDesc);
    int index = getIndex(mHeap, mSize, data); 

    return index;
}

/* 
 * 返回data在二叉堆中的索引
 *
 * 返回值:
 *     存在 -- 返回data在数组中的索引
 *     不存在 -- -1
 */
template <class T>
int HeapSort<T>::getIndex(T arr[], int len, T data)
{
    for(int i=0; i<len; i++)
        if (data==arr[i])
            return i;
    return -1;
}

/**
 * 获取数据,数组大小
 **/
template <class T>
T* HeapSort<T>::getHeap()
{
    return mHeap;
}

template <class T>
int HeapSort<T>::getSize()
{
    return mSize;
}

template <class T>
void HeapSort<T>::print()
{
    for (int i=0; i<mSize; i++)
        cout << i << ":" << mHeap[i] << " ";
    cout << endl;
}
/*
 * 数组打印 arr(数组), len(长度)
 */
template <class T>
void HeapSort<T>::print(T arr[], int len)
{
    for (int i=0; i<len; i++)
        cout << i << ":" << arr[i] << " ";
    cout << endl;
}

 调用

int _tmain(int argc, _TCHAR* argv[])
{
    int a[] = {10, 40, 30, 60, 90, 75, 70, 20, 50, 80};
    int len=(sizeof(a)) / (sizeof(a[0])) ;
    HeapSort<int>* tree=new HeapSort<int>();

    // 排序
    tree->filtersort(a, len, NULL);
    tree->print(a, len);

    // 查询
    int index = tree->getIndex(a, len, 40);
    cout << "查询:" << index << endl;

    // 删除后,数据数据存储在MaxHeap中
    int index_r = tree->remove(a, len, 40, true);
    cout << "删除:" << index_r << endl;
    tree->print();

    // 插入
    int index_i = tree->insert( a, len, 35, true);
    cout << "插入:" << index_i << endl;
    tree->print();

    //=================================
    system("pause");
    return 0;
}

THE END

posted on 2015-05-26 20:51  AKever  阅读(158)  评论(0)    收藏  举报