选择排序
依次选择数组中的最小值(从小到大),并按顺序排放。
从第一个数开始,依次遍历数组中的数据,找出最小值,并与第一个数交换位置;
从第二个数开始,依次遍历(剩余)数组中的数据,找出最小值,并与第二个数交换位置;
... ...
堆排序
堆的概念:在一颗完全二叉树中,子结点的值总是小于父结点的值(大根堆),或者子结点的值总是大于父结点的值(小根堆)。
例如:int array[10] = {9,8,7,1,2,3,6,5,4,0};
层序存放:
调整后的输出:
(这里只是将5和1做了交换)
3. 将根结点与尾结点进行交换(此时的尾结点不一定是最小值)
{
temp = array[0];
array[0] = array[heapSize];
array[heapSize] = temp;
heapSize--;
}
因为此时根结点为最大值,即:将最大值挪动到最后位置,此后不再“关注”。
输出:
(这里将9和0做了交换,9不再参与之后的比较、调整)
4. (递归)重复步骤2
调整后的输出:
输出:
(这里将8和0做了交换,8不再参与之后的比较、调整)
6. (递归)重复步骤2和3
最终,得到结果:
对应的数组array[10] = {0,1,2,3,4,5,6,7,8,9};
在理解“堆排序”之前,我有2个疑惑:
1. 数组的存储为什么不调整为BST树?
数组如果表示为BST的存储,BST的树高不确定,将会借助更大的存储空间;(如果想降低树的高度,必须旋转)
2. 如果数据本来就是按照升序排列(小顶堆),然后又来构建大顶堆,岂不是多此一举?
依次选择数组中的最小值(从小到大),并按顺序排放。
从第一个数开始,依次遍历数组中的数据,找出最小值,并与第一个数交换位置;
从第二个数开始,依次遍历(剩余)数组中的数据,找出最小值,并与第二个数交换位置;
... ...
堆排序
堆的概念:在一颗完全二叉树中,子结点的值总是小于父结点的值(大根堆),或者子结点的值总是大于父结点的值(小根堆)。
我想,堆排序之所以也属于选择排序,是因为它总是从堆中选择最大值(降序是最小值)交换于数据尾部。
排序过程:
1.我们将数组“理解(视)为”逻辑中的二叉树;例如:int array[10] = {9,8,7,1,2,3,6,5,4,0};
层序存放:
2.将二叉树调整为二叉堆(如果是升序排列,使用大根堆)
从最后一个有孩子的结点的位置(node=(length -1)/2)开始,调整“父”与“子”结点的位置(使子结点的值总是小于父结点的值,左右子结点大小无所谓),直到调整至根结点。调整后的输出:
(这里只是将5和1做了交换)
3. 将根结点与尾结点进行交换(此时的尾结点不一定是最小值)
{
temp = array[0];
array[0] = array[heapSize];
array[heapSize] = temp;
heapSize--;
}
因为此时根结点为最大值,即:将最大值挪动到最后位置,此后不再“关注”。
输出:
(这里将9和0做了交换,9不再参与之后的比较、调整)
4. (递归)重复步骤2
调整后的输出:
输出:
(这里将8和0做了交换,8不再参与之后的比较、调整)
6. (递归)重复步骤2和3
最终,得到结果:
对应的数组array[10] = {0,1,2,3,4,5,6,7,8,9};
在理解“堆排序”之前,我有2个疑惑:
1. 数组的存储为什么不调整为BST树?
数组如果表示为BST的存储,BST的树高不确定,将会借助更大的存储空间;(如果想降低树的高度,必须旋转)
2. 如果数据本来就是按照升序排列(小顶堆),然后又来构建大顶堆,岂不是多此一举?
这就是为什么堆排序的时间复杂度(最小、平均、最大)总是O(NlogN)。
#include<stdio.h>
//打印
void display(int array[], int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", array[i]);
}
printf("\n");
}
//选择排序
void selectionSort(int array[], int n)
{
int i, j, index, value;
//i,可以理解为数组下标,从i开始遍历,查找数组中的最小值;
//当找到最小值,放置到下标i的位置,然后从i+1继续查找最小值。
for (i = 0; i < n - 1; i ++)
{
//index,最小值下标
index = i;
//最小值
value = array[i];
//循环遍历找到最小值
for (j = i + 1; j < n; j ++)
{
if (value > array[j])
{
index = j;
value = array[j];
}
//display(array, n);
}
//寻得本轮最小值后,(通过交换)放置到适当的位置。
array[index] = array[i];
//value即当前最小值,把它放置到位置i
array[i] = value;
display(array, n);
}
}
//堆调整
void heapAdjust(int array[], int node, int heapSize)
{
display(array, heapSize+1);
int leftChild, rightChild, largest, temp;
//左孩子结点
leftChild = 2*node+1;
//右孩子结点
rightChild = 2*node + 2;
//比较当前结点、左孩子、右孩子中的最大值
if(leftChild <= heapSize && array[leftChild] > array[node])
{
largest = leftChild;
}
else
{
largest = node;
}
if( rightChild <= heapSize && array[rightChild] > array[largest])
{
largest = rightChild;
}
//如果最大值不是“结点值”,“结点值”与其孩子中的“大值”交换。
if(largest != node)
{
temp = array[node];
array[node] = array[largest];
array[largest] = temp;
heapAdjust(array, largest, heapSize);
}
}
//构建大顶堆,
//如果本来数据就是按照升序排列,然后又来构建大顶堆,岂不是多此一举?
void buildHeap(int array[], int length)
{
int node, heapSize;
//heapSize实际与数据下标对应,所以要减1
heapSize = length - 1;
//最后一个有孩子的节点的位置 node = (length -1) / 2
for( node=(length-1)/2; node >= 0; node--)
{
heapAdjust(array, node, heapSize);
}
}
//堆排序
void heapSort(int array[], int length)
{
buildHeap(array, length);
int heapSize, i, temp;
heapSize = length - 1;
//heapsize,堆的最末一位
for( i=heapSize; i >= 0; i--)
{
//array[0],堆顶,即堆内最大数据;与array[heapSize]交换,array[heapSize]是堆末数据(不一定为最小数据)
temp = array[0];
array[0] = array[heapSize];
array[heapSize] = temp;
//堆内最大数据被放置到当前堆末位后,--降堆,
heapSize--;
heapAdjust(array, 0, heapSize);
}
display(array, length);
}
int main()
{
printf("==============Test Selection Sort ==============\n");
int array[10] = {9,8,7,1,2,3,6,5,4,0};
//int array[10] = {9,8,7,6,5,4,3,2,1,0};
//int array[10] = {0,1,2,3,4,5,6,7,8,9};
selectionSort(array, 10);
printf("==============Test Heap Sort ==============\n");
int array10[10] = {9,8,7,1,2,3,6,5,4,0};
//int array11[10] = {9,8,7,6,5,4,3,2,1,0};
//int array12[10] = {0,1,2,3,4,5,6,7,8,9};
heapSort(array10, 10);
}