简单选择排序就是每次从i到N-1中选择最小的数,然后放在第i个位置,其算法复杂度为O(N2);
堆排序是简单选择排序的改进,通过建立最大堆,每次将最大堆的根节点取出放在最后的位置,然后再重新调整为最大堆,时间复杂度为O(NlogN)。
- 简单排序算法
void Select_Sort(SqList *L)
/*简单选择排序,算法复杂度为O(N2),不稳定*/
{
int postion;
for (int i = 0; i < L->Length; i++)
{
postion = ScanfForMin(*L, i, L->Length - 1);//每次从i到N-1中找到最小的元素的位置
Swap(&L->data[postion], &L->data[i]);
}
}
2.堆排序算法
void Heap_Sort(SqList *L)
/*堆排序*/
{
BuildMaxHeap(L);//建立最大堆
for (int i = L->Length - 1; i >= 0; i--)
{
Swap(&L->data[0], &L->data[i]);//把最大的第一个结点和最后一个交换位置
PercDown(L, 0, i-1);//向下调整
}
}
堆排序算法最核心的部分是建立最大堆和最大堆的调整,调整方法为向下过滤法。
向下过滤算法:在一棵子树中,对于根结点parent,如果parent的元素值比child中最大的元素要小则交换parent和child的位置。然后令parent=child,继续比较。这样这棵子树为最大堆。
void PercDown(SqList *L, int root, int end)
{/*向下过滤*/
int child, parent;
parent = root;
for (parent = root; (parent*2+1)<end; parent=child) // parent有孩子
{
child = parent * 2 + 1;//左孩子
if ((child + 1) <= end && L->data[child] < L->data[child + 1]) //从左右孩子中找到最大的孩子
child++;
if (L->data[parent] < L->data[child])//如果孩子比父亲大就交换位置
Swap(&L->data[parent], &L->data[child]);
else//如果parent比child大则退出循环
break;
}
}
建立最大堆
我们选择从下到上一步步建立最大堆,逐步向下调整。
void BuildMaxHeap(SqList *L)
/*建立最大堆*/
{
if (L->Length % 2 == 0)//末结点下标为奇数
{
for (int i = (L->Length - 1) / 2; i >= 0; i--)
{
PercDown(L, i, L->Length - 1);
}
}
else//末结点下标为偶数
{
for (int i = (L->Length - 2) / 2; i >= 0; i--)
{
PercDown(L, i, L->Length - 1);
}
}
}
完整的测试代码
// Selection_Sort.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 100
typedef int ElementType;
typedef struct
{
ElementType data[MaxSize];
int Length;
}SqList;
void Swap(ElementType *a, ElementType *b)
{
ElementType tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void DisplaySqList(SqList L)
/*打印序列*/
{
int i;
for (i = 0; i < L.Length; i++)
{
printf("%-4d", L.data[i]);
}
printf("\n");
}
int ScanfForMin(SqList L, int Left, int Right)
/*在序列中找出最小的元素所在的位置*/
{
int pos=Left;
ElementType tmp;
for (int i = Left; i <= Right; i++)
{
tmp = L.data[pos];
if (tmp > L.data[i])
pos = i;
}
return pos;
}
void Select_Sort(SqList *L)
/*简单选择排序,算法复杂度为O(N2),不稳定*/
{
int postion;
for (int i = 0; i < L->Length; i++)
{
postion = ScanfForMin(*L, i, L->Length - 1);//每次从i到N-1中找到最小的元素的位置
Swap(&L->data[postion], &L->data[i]);
}
}
void PercDown(SqList *L, int root, int end)
{/*向下过滤*/
int child, parent;
parent = root;
for (parent = root; (parent*2+1)<end; parent=child) // parent有孩子
{
child = parent * 2 + 1;//左孩子
if ((child + 1) <= end && L->data[child] < L->data[child + 1]) //从左右孩子中找到最大的孩子
child++;
if (L->data[parent] < L->data[child])//如果孩子比父亲大就交换位置
Swap(&L->data[parent], &L->data[child]);
else//如果parent比child大则退出循环
break;
}
}
void BuildMaxHeap(SqList *L)
/*建立最大堆*/
{
if (L->Length % 2 == 0)//末结点下标为奇数
{
for (int i = (L->Length - 1) / 2; i >= 0; i--)
{
PercDown(L, i, L->Length - 1);
}
}
else//末结点下标为偶数
{
for (int i = (L->Length - 2) / 2; i >= 0; i--)
{
PercDown(L, i, L->Length - 1);
}
}
}
void Heap_Sort(SqList *L)
/*堆排序*/
{
BuildMaxHeap(L);//建立最大堆
for (int i = L->Length - 1; i >= 0; i--)
{
Swap(&L->data[0], &L->data[i]);//把最大的第一个结点和最后一个交换位置
PercDown(L, 0, i-1);//向下调整
}
}
int main()
{
SqList L, L1;
ElementType A[] = { 1,34,23,45,2,4,66,32,65,46,31,44 };
int len = sizeof(A) / sizeof(A[0]);
for (int i = 0; i < len; i++)
{
L.data[i] = A[i];
}
L.Length = len;
L1 = L;
printf("排序前:\n");
DisplaySqList(L);
printf("简单选择排序:\n");
Select_Sort(&L);
DisplaySqList(L);
printf("堆排序:\n");
Heap_Sort(&L1);
DisplaySqList(L1);
}
程序运行截图: