数据结构与算法——排序之堆排序(递归与迭代)

堆排序源码(时O(N*logN),空O(1))

/*
    这里不妨先回忆一下,完全二叉树的性质:
    如果对一颗有n个结点的完全二叉树的结点按层序编号(从上到下,从左到右),对任意结点i(1 <= i <= n):
    1 如果i= 1,则结点i是二叉树的根,无双亲;如果i > 1,则其双亲是节点i/2.
    2 如果2i > 0,则结点i无左孩子(其实i结点就是叶子结点);否则左孩子是结点2i.
    3 如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1.
    
    注意的是:上述结点是从1开始算的,若从0开始算根节点,会有点不一样。
*/
​
void MySwap(int arr[], int a, int b) {
    int tmp = arr[a];
    arr[a] = arr[b];
    arr[b] = tmp;
}
​
/*
    调整堆
    @param arr 待调整的数组
    @param index 待调整的节点的下标
    @param len 待调整的数组的长度
*/
void HeapAdjust(int arr[], int index, int len) {
​
    //先保存当前节点的下标
    int max = index;
​
    //保存左右孩子的数组下标
    int lchild = index * 2 + 1;
    int rchild = index * 2 + 2;
​
    if (lchild < len && arr[max] < arr[lchild])
        max = lchild;
​
    if (rchild < len && arr[max] < arr[rchild])
        max = rchild;
​
    //判断是否需要交换节点
    if (max != index)
    {
        MySwap(arr, max, index);
        HeapAdjust(arr, max, len);
    }
}
​
​
//堆排序
void HeapSort(int arr[], int len) {
    
    //初始化堆
    for (int i = len / 2 -1; i >= 0; i--)
        HeapAdjust(arr, i, len);
​
    //交换堆顶元素和最后一个元素
    for (int i = len - 1; i >= 0; i--)
    {
        MySwap(arr, 0, i);
        HeapAdjust(arr, 0, i);
    }
}

对于上面的堆排序算法,是比较好理解的,但是还是因为用到了递归,导致空间复杂度为log2N。林伟一种方式采用迭代的方法,那么空间复杂度就是O(1)啦。

//HeapSort()函数就不要变了,我们修改上面的HeapAdjust()函数
//迭代的算法
void HeapAdjust2(int arr[], int index, int len) {
​
    //先保存当前节点的下标
    int max = index;
​
    //保存左孩子的数组下标
    int lchild = index * 2 + 1;
​
    while (lchild < len)
    {
        if (lchild + 1 < len && arr[lchild] < arr[lchild + 1])
            lchild++;
        if (arr[lchild] > arr[max])
        {
            MySwap(arr, lchild, max);       //交换节点的值
            max = lchild;                   //对index上的值再继续往下
            lchild = lchild * 2 + 1;
        }
        else
            break;
    }
}

写了才发现,其实迭代算法也是很简单的。这里我想说一点,在做类似于空间复杂度优化时,如若发现未优化前的代码是采用递归的方法求解的,那么我们的优化思路就是如何将递归改为迭代的方法求解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值