C++数据结构作业——堆排序算法的改进

记录作业题

一、题目要求

        假设定义最大堆为满足如下性质的完全三叉树:

  1. 空树为堆;
  2. 每个结点最多有3棵子树,且结点的值不小于所有子树根的值,且所有子树均为最大堆。

        按上述述要求完成三叉堆的存储结构设计,再实现三叉堆的向下调整算法,最后完成利用三叉堆进行排序的算法。要求利用大数据量进行测试,同原有堆排序算法在时间上进行对比分析。

二、二叉堆代码

        本题算法逻辑与二叉堆代码一致,因此先放出课本上二叉堆代码。

        要注意的是,长度为n的堆中各元素的序号是从0开始,到n-1结束。因此对于序号为i的节点而言,其左孩子序号为2*i+1,右孩子序号为2*i+2。

template <class ElemType>
void HeapSort(ElemType elem[], int n)
// 操作结果:对数组elem进行堆排序
{
	int i;
	for (i = (n-2)/2; i >= 0; --i) // 初始建堆,将elem[0 .. n - 1]调整成最大堆
		FilterDown(elem, i, n - 1);
	for (i = n - 1; i > 0; --i)
    {  // 第i趟堆排序
		Swap(elem[0], elem[i]);
			// 将堆顶元素和当前未经排序的子序列elem[0 .. i]中最后一个元素交换
		FilterDown(elem, 0, i - 1);	// 将elem[0 .. i - 1]重新调整为最大堆
	}
}
template <class ElemType>
void FilterDown(ElemType elem[], int low, int high)
// 操作结果:将以low为根的子树调整成为一个最大堆
{
    int f = low, i = 2 * low + 1;
    ElemType e = elem[low];
    while (i <= high)
    {			// f为被调整结点,i为f的最大孩子
		if (i < high && elem[i] < elem[i + 1])
			i++;				// f有右孩子,且右孩子的值更大, i指向右孩子
		if (e < elem[i])
		{	// 孩子的值大于其双亲,则进行向下调整
			elem[f] = elem[i];
            f = i;
            i = 2 * f + 1;
		}
		else
            break;
	}
	elem[f] = e;
}

三、思路

        对于排序部分,三叉堆与二叉堆的整体逻辑一模一样:都是将堆中具有最大关键字的元素elem[0]与堆的最后一个元素交换位置,然后调整堆中除最后一个元素以外的元素,使之成为最大堆,再将新的elem[0]与堆的最后一个元素交换位置……不断重复此过程直到将所有元素排好序。由于逻辑相同,所以只需要根据完全三叉树的性质对相应数字做修改即可,也就是在寻找最后一个分支节点i时,采取计算公式i=(n-1)/3,其余部分代码完全相同。

        三叉堆和二叉堆最大的不同之处出现在调整函数。因为三叉堆的一个根节点最多会有三个孩子,所以双亲结点与孩子结点的序号对应会有不同;在寻找被调整结点的最大的孩子时,也要比二叉堆的对应环节更加复杂。具体改变如下:

  1. 对于序号为f的被调整结点,其最左边的孩子序号为3*f+1。
  2. 为了找到三个孩子中关键字最大的孩子j,需要使用多重判断。如果最左边的孩子小于中间的孩子,则再比较中间的孩子与最右边的孩子,j表示后两者中较大的孩子;如果最左边的孩子大于中间的孩子且小于最右边的孩子,则j表示最右边的孩子;如果以上两种情况都不成立,则最左边的孩子为最大的孩子,j表示最左边的孩子。

 四、三叉堆代码

经过以上分析,通过仿照二叉堆代码,得到三叉堆代码如下:

template <class ElemType>
void HeapSort3(ElemType elem[], int n)
{
    int i;
    for(i = (n-1)/3; i >= 0; --i)
        FilterDown3(elem, i, n - 1);
    for(i = n - 1; i > 0; --i)
    {
        Swap(elem[0], elem[i]);
        FilterDown3(elem, 0, i - 1);
    }
}
template <class ElemType>
void FilterDown3(ElemType elem[], int low, int high)
{
    int f = low, j = 3 * low + 1;
    ElemType e = elem[low];
    while(j <= high)
    {
        if(j < high && elem[j] < elem[j + 1])
        {
            j++;
            if(j < high && elem[j] < elem[j + 1])
                j++;
        }
        else if(j + 1 < high && elem[j] < elem[j + 2])
            j = j + 2;
        if(e < elem[j])
        {
            elem[f] = elem[j];
            f = j;
            j = 3 * f + 1;
        }
        else
            break;
    }
    elem[f] = e;
}

        用大数据量进行测试后发现,三叉堆的排序算法比原先二叉堆排序算法的速度要更快一些。分析认为这是由于在三叉堆向下调整函数的每一次循环中,比较的节点数量更多,因此将数组化为最大堆所需的循环更少,消耗的时间也就更少。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值