数据结构与算法——排序之堆排序(递归与迭代)
堆排序源码(时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; } }
写了才发现,其实迭代算法也是很简单的。这里我想说一点,在做类似于空间复杂度优化时,如若发现未优化前的代码是采用递归的方法求解的,那么我们的优化思路就是如何将递归改为迭代的方法求解。
下一篇:
二叉树前序遍历--递归