选择排序
顺序表存储结构
#define MAXSIZE 20
typedef int KeyType;
typedef int InfoType;
typedef struct
{
KeyType key;
InfoType info;
}RedType;
typedef struct
{
RedType r[MAXSIZE+1];
int lenght;
}SqList;
简单选择排序
//简单选中排序
void SelectSort(SqList *L)
{
int i,j,k;
for(i=1;i<L->lenght;i++) //这里的i<L->length 没有=,相当于进行选择length-1次
{
k=i;
for(j=i+1;j<=L->lenght;j++)
if(L->r[j].key < L->r[k].key) k=j; //逐个比较,用k记录最小值下标
if(k!=i)
{
RedType tmp = L->r[i];
L->r[i] = L->r[k];
L->r[k] = tmp;
}
}
}
时间复杂度分析
最好的情况下,不需要移动;最坏的情况下,需移动3(n-1)次(每对比一次需要移动三次元素);
无论初始排序如何,关键字对比次数都是n(n-1)/2≈O(n²/2)。
空间复杂度分析
和冒泡排序一样只需要一个交换辅助空间,空间复杂度为O(1)。
堆排序
图片出自:链接
//堆排序
/*
堆调整,将一个堆调整为大根堆
*/
void HeapAdjust(SqList *L,int s,int m) //s是开始结点下标,m是结束结点下标
{
int i;
RedType rc = L->r[s];
for(i=2*s;i<=m;i*=2) //i<=m 并不是i<=L->lenght 眼瞎写错 debug一个多小时没发现
{
if(i<m && L->r[i].key < L->r[i+1].key) i++; //i<m 表示还有兄弟结点
if(rc.key >= L->r[i].key) break; //根结点大于子节点最大值,则结束调整
L->r[s] = L->r[i]; //将左右子节点最大的那个与根结点对换
s = i; //原最大值的子节点位置(下标)
}
L->r[s] = rc; //原根结点插入
}
/*
创建堆:将一个无序表调整为大根堆
*/
void HeapCreate(SqList *L)
{
int n = L->lenght;
for(int i=n/2;i>=1;i--) //从最后一个非叶子结点开始倒序都进行一次调整,直到第一个根结点调整完成
HeapAdjust(L,i,n);
}
/*
堆排序:对顺序表进行堆排序输出
*/
void HeapSort(SqList *L)
{
HeapCreate(L); //创建一个大根堆
for(int i=L->lenght;i>1;i--)
{
RedType tmp = L->r[1]; //堆顶与最后一个交换
L->r[1] = L->r[i];
L->r[i] = tmp;
HeapAdjust(L,1,i-1); //对堆的i-1个结点继续进行调整
}
}
时间复杂度分析
最坏情况下,时间复杂度为O(nlog₂n)。实验表明,平均性能接近于最坏情况下的性能。
空间复杂度分析
仅需要一个交换辅助空间,因此空间复杂度为O(1)。
测试代码整合
#include <stdio.h>
#define MAXSIZE 20
typedef int KeyType;
typedef int InfoType;
typedef struct
{
KeyType key;
InfoType info;
}RedType;
typedef struct
{
RedType r[MAXSIZE+1];
int lenght;
}SqList;
//简单选中排序
void SelectSort(SqList *L)
{
int i,j,k;
for(i=1;i<=L->lenght;i++)
{
k=i;
for(j=i+1;j<=L->lenght;j++)
if(L->r[j].key < L->r[k].key) k=j; //逐个比较,用k记录最小值下标
if(k!=i)
{
RedType tmp = L->r[i];
L->r[i] = L->r[k];
L->r[k] = tmp;
}
}
}
//堆排序
/*
堆调整,将一个堆调整为大根堆
*/
void HeapAdjust(SqList *L,int s,int m)
{
int i;
RedType rc = L->r[s];
for(i=2*s;i<=m;i*=2) //i<=m 并不是i<=L->lenght 眼瞎写错 debug一个多小时没发现
{
if(i<m && L->r[i].key < L->r[i+1].key) i++;
if(rc.key >= L->r[i].key) break; //根结点大于子节点最大值,则结束调整
L->r[s] = L->r[i]; //将左右子节点最大的那个与根结点对换
s = i; //原最大值的子节点位置(下标)
}
L->r[s] = rc; //原根结点插入
}
/*
创建堆:将一个无序表调整为大根堆
*/
void HeapCreate(SqList *L)
{
int n = L->lenght;
for(int i=n/2;i>0;i--) //从最后一个非叶子结点都进行一次调整,直到第一个根结点调整完成
HeapAdjust(L,i,n);
}
/*
堆排序:对顺序表进行堆排序输出
*/
void HeapSort(SqList *L)
{
HeapCreate(L); //创建一个大根堆
for(int i=L->lenght;i>1;i--)
{
RedType tmp = L->r[1]; //堆顶与最后一个交换
L->r[1] = L->r[i];
L->r[i] = tmp;
HeapAdjust(L,1,i-1); //对堆的i-1个结点继续进行调整
}
}
int main()
{
SqList L;
printf("简单选择排序\n");
printf("需要创建一个长度为多少的顺序表:");
scanf("%d",&L.lenght);
printf("请输入%d个元素创建顺序表:",L.lenght);
for(int i=1;i<=L.lenght;i++)
scanf(" %d",&L.r[i].key);
SelectSort(&L);
printf("简单选择排序:");
for(int i=1;i<=L.lenght;i++)
printf("%d ",L.r[i].key);
printf("\n\n堆排序\n");
SqList L1;
printf("需要创建一个长度为多少的顺序表:");
scanf("%d",&L1.lenght);
printf("请输入%d个元素创建顺序表:",L1.lenght);
for(int i=1;i<=L1.lenght;i++)
scanf(" %d",&L1.r[i].key);
HeapSort(&L1);
printf("堆排序:");
for(int i=1;i<=L1.lenght;i++)
printf("%d ",L1.r[i].key);
return 0;
}