排序算法--堆排序
2006-12-31 18:25
260 查看
要讨论堆排序,首先就要简单的讨论一下堆这种数据结构.
堆排序所用到的二叉堆可以用数组表示出来,而且它可以被看作是一棵完全二叉树.出了树的最后一层,其它层应当是被填满的.
每个节点除了最后一层的叶子节点,从不同的角度观察都具备了不同的角色.假设有一个节点i,我们应当注意它产生的三个不同的角色.
Parent(i) = i / 2;
LeftChild(2i);
RightChild(2i + 1);
堆结构应当满足的性质是:
A[Parent(i)] > A[i]
既子节点最多只能等于父节点,而不能大于父节点.所以当有节点违反这个性质的时候就产生了一种调整的方法,使其符合堆的性质.过程就是查看节点i的LeftChild(i)和RightChild(i)是否大于节点i,如果违反了堆的性质,则把节点i和其较大的子节点交换,然后再递归的查看交换过的节点是否又违反了堆的性质,然后不停的调整,直到堆中所有的节点都没有违反堆的性质.
完成以上的步骤以后,整个数组中的最大值就位于了根节点的位置上,一个大根堆就这样建成了.接下来我们就可以用这个大根堆来进行堆排序了.
堆排序:
算法:
当一个大根堆建好的时候,数组中最大的节点就位于了A[1]的位置,既根节点的位置,我们把这个最大值和堆中的最后一个节点A
交换,并把A
从堆中去掉,将堆的规模减小1.堆排序的一步就完成了.同时因为交换上去的节点再一次的破坏了堆的性质,我们再从新的建立一个大根堆,完成以后,数据数组中的次大元素就位于了根节点的位置,接下来继续对它进行刚才最大元素所经历的操作,照此循环往复,就可以完成堆排序了.完成的时候,数组的第一个节点就是数据中最小的节点,最后一个是最大的节点.
代码:
#include <stdio.h>
#define Parent(i) i / 2
#define Left(i) 2 * i
#define Right(i) (2 * i + 1)
const int MAX = 11;
void Heapify(int *A, int i, int heapSize)
...{
int left, right, parent, largest, temp, done;
done = 0;
largest = -1;
while(Parent(i) <= heapSize && i >= Parent(i))
...{
left = Left(i);
right = Right(i);
parent = Parent(i);
if(left < heapSize && A[left] > A[i])
largest = left;
else
largest = i;
if(right < heapSize && A[right] > A[largest])
largest = right;
if(largest != i)
...{
temp = A[largest];
A[largest] = A[i];
A[i] = temp;
}
i++;
}
}
void buildHeap(int *A, int heapSize)
...{
int i;
for(i = (MAX - 1) / 2; i > 1; i--)
Heapify(A, i, heapSize);
}
void heapSort(int *A)
...{
int i, temp, heapSize;
heapSize = MAX - 1;
buildHeap(A, heapSize);
for(i = MAX - 1; i >= 1; i--)
...{
temp = A[i];
A[i] = A[1];
A[1] = temp;
heapSize -= 1;
Heapify(A, 1, heapSize);
}
}
int main()
...{
int A[MAX];
int i;
int nums = MAX - 1;
printf("Please input %d numbers: ", nums);
for(i = 1; i < MAX; i++)
scanf("%d", &A[i]);
heapSort(A);
for(i = 1; i < MAX; i++)
printf("%d ", A[i]);
return 0;
}
堆排序的时间复杂度的上界是O(nlog2n),现在还没有明确的下界.不过实践中堆排序要比使用Sedgewick增量序列的希尔排序慢.并且因为需要不停的建堆,所以元素较少的时候不推荐用堆排序.
堆排序所用到的二叉堆可以用数组表示出来,而且它可以被看作是一棵完全二叉树.出了树的最后一层,其它层应当是被填满的.
每个节点除了最后一层的叶子节点,从不同的角度观察都具备了不同的角色.假设有一个节点i,我们应当注意它产生的三个不同的角色.
Parent(i) = i / 2;
LeftChild(2i);
RightChild(2i + 1);
堆结构应当满足的性质是:
A[Parent(i)] > A[i]
既子节点最多只能等于父节点,而不能大于父节点.所以当有节点违反这个性质的时候就产生了一种调整的方法,使其符合堆的性质.过程就是查看节点i的LeftChild(i)和RightChild(i)是否大于节点i,如果违反了堆的性质,则把节点i和其较大的子节点交换,然后再递归的查看交换过的节点是否又违反了堆的性质,然后不停的调整,直到堆中所有的节点都没有违反堆的性质.
完成以上的步骤以后,整个数组中的最大值就位于了根节点的位置上,一个大根堆就这样建成了.接下来我们就可以用这个大根堆来进行堆排序了.
堆排序:
算法:
当一个大根堆建好的时候,数组中最大的节点就位于了A[1]的位置,既根节点的位置,我们把这个最大值和堆中的最后一个节点A
交换,并把A
从堆中去掉,将堆的规模减小1.堆排序的一步就完成了.同时因为交换上去的节点再一次的破坏了堆的性质,我们再从新的建立一个大根堆,完成以后,数据数组中的次大元素就位于了根节点的位置,接下来继续对它进行刚才最大元素所经历的操作,照此循环往复,就可以完成堆排序了.完成的时候,数组的第一个节点就是数据中最小的节点,最后一个是最大的节点.
代码:
#include <stdio.h>
#define Parent(i) i / 2
#define Left(i) 2 * i
#define Right(i) (2 * i + 1)
const int MAX = 11;
void Heapify(int *A, int i, int heapSize)
...{
int left, right, parent, largest, temp, done;
done = 0;
largest = -1;
while(Parent(i) <= heapSize && i >= Parent(i))
...{
left = Left(i);
right = Right(i);
parent = Parent(i);
if(left < heapSize && A[left] > A[i])
largest = left;
else
largest = i;
if(right < heapSize && A[right] > A[largest])
largest = right;
if(largest != i)
...{
temp = A[largest];
A[largest] = A[i];
A[i] = temp;
}
i++;
}
}
void buildHeap(int *A, int heapSize)
...{
int i;
for(i = (MAX - 1) / 2; i > 1; i--)
Heapify(A, i, heapSize);
}
void heapSort(int *A)
...{
int i, temp, heapSize;
heapSize = MAX - 1;
buildHeap(A, heapSize);
for(i = MAX - 1; i >= 1; i--)
...{
temp = A[i];
A[i] = A[1];
A[1] = temp;
heapSize -= 1;
Heapify(A, 1, heapSize);
}
}
int main()
...{
int A[MAX];
int i;
int nums = MAX - 1;
printf("Please input %d numbers: ", nums);
for(i = 1; i < MAX; i++)
scanf("%d", &A[i]);
heapSort(A);
for(i = 1; i < MAX; i++)
printf("%d ", A[i]);
return 0;
}
堆排序的时间复杂度的上界是O(nlog2n),现在还没有明确的下界.不过实践中堆排序要比使用Sedgewick增量序列的希尔排序慢.并且因为需要不停的建堆,所以元素较少的时候不推荐用堆排序.
相关文章推荐
- Java-时间复杂度为O(nlogn)的排序算法(快速排序, 归并排序, 堆排序, 希尔排序)
- 【排序算法】-堆排序
- 排序算法(1):插入排序,选择排序,希尔排序,堆排序
- 排序算法-堆排序
- 写个堆排序,快速排序等一些排序算法
- 排序算法之四--堆排序
- 排序算法总结4-堆排序
- 排序算法----堆排序
- 排序算法(七) 堆排序
- 排序算法---堆排序
- 常用的排序算法(快速排序、插入排序、希尔排序、堆排序、冒泡排序、选择排序、归并排序)
- 排序算法的数组实现 -- 堆排序(二)
- 排序算法思想——归并排序、堆排序、shell排序
- 【排序算法】堆排序的分析
- 排序算法之 堆排序
- 排序算法(五) —— 堆排序
- 常见排序算法总结与实现(冒泡、插入、选择、希尔、堆排序、归并、快排)
- 排序算法之堆排序
- 排序算法:希尔、归并、快速、堆排序
- 排序算法之堆排序