一、插入排序
1、直接插入排序
【直接插入排序的基本思想】顺序地把待排序的数据元素按其关键子的大小插入到已排序数据元素子集合的适当位置。
子集合的数据元素个数从只有一个数据元素开始,逐次增大,当子集合大小最终和集合大小相同时,排序完毕。
设待排序的n个数据元素存放在数组a中,初始时,子集合a[0] 已排好序;第一次循环准备把数据元素a[1] 插入到已排好序的子集合中,
这只需要比较a[0].key和a[1].key,若a[0].key<=a[1].key,则说明序列已有序,否则将a[1]插入到a[0]之前,这样子集合的大小增大为2;
第二次循环准备把数据元素a[2]插入到已排好序的子集合中,这需要先比较a[2].key和 a[1].key以确定是否把a[2]插入到a[1]之前,
然后比较a[2].key和a[0].key来确定是否把a[2]插入到a[0]之前;这样的循环过程一直进行到a[n-1]插入完为止。这时,数据元素
集合a[0],a[1],a[2],...,a[n-1]全部排好序了。
直接插入排序算法:
void InsertSort(DataType a[], int n)
//用直接插入法对数据元素a[0]~a[n-1]进行排序
{
int i,j;
DataType temp;
for(i = 0;i < n-1;i++)
{
temp = a[i + 1];
j = i;
while(j > -1 && temp.key < a[j].key)
{
a[j + 1] = a[j];
j--;
}
a[j + 1] = temp;
}
}
2、希尔排序
【希尔排序的基本思想】把待排序的数据元素分成若干个小组,对同一小组內的数据元素用直接插入法排序;小组的个数逐次减少;
当完成了所有数据元素都在一个小组内的排序后,排序过程结束。希尔排序又成缩小增量排序。
希尔排序是在分组概念上的直接插入排序,即在不断减少组内的元素个数时把原各小组的数据元素插入到新组中的合适位置上。
希尔排序算法:
void ShellSort(DataType a[], int n, int d[], int numOfD)
//用希尔排序法对元素a[0]~a[n-1]排序,d[0]~d[numOfD-1]为希尔增量值
{
int i, j, k, m, span;
DataType temp;
for(m=0;m<numOfD;m++) //共numOfD次循环
{
span = d[m]; //取本次的增量值
for(k=0;k<span;k) //共span个小组
{
//组内是直接插入排序,区别是,每次不是增1而是增span
for(i=k;i<n-span;i=i+span)
{
temp = a[i + span];
j = i;
while(j>-1 && temp.key<a[j].key)
{
a[j + span] = a[j];
j = j - span;
}
a[j + span] = temp;
}
}
}
}
二、选择排序
1、直接选择排序
【直接选择排序的基本思想】 从待排序的数据元素集合中选取关键字最小的数据元素并将它与原始数据元素集合中的
第一个数据元素交换位置,然后从包括第二个位置上数据元素的集合中选取关键字最小的数据元素,
并将它与原始数据元素集合中的第二个数据元素交换位置,重复操作,直到数据元素集合中只剩下一个数据元素为止。
直接选择排序算法:
void SelectSort(DataType a[], int n)
//用直接选择排序法对数组元素a[0]~a[n-1] 进行排序
{
int i, int j, small;
DataType temp;
for(i = 0;i < n-1;j++)
{
small = i;
for(j = i+1;j < n;j++)
if(a[j].key < a[small],key)
small = j;
if(small != i)
{
temp = a[i];
a[i] = a[small];
a[small] = temp;
}
}
}
2、堆排序
【堆排序的基本思想】在直接选择排序中,待排序的数据元素集合构成一个线性结构,要从有n个数据元素的线性结构中
选择出一个最小的数据元素需要比较n-1次。如果能把待排序的数据元素集合构成一个完全二叉树结构,则每次选择出一个最大(或最小)
的数据元素只需要比较完全二叉树的深度次,即lbn次,则排序算法的时间复杂度就是O(nlbn)。
@1.调节非叶节点啊a[h]使之满足最大堆的函数:
void CreateHeap (DataType a[],int n,int h)
//调节非叶节点a[h]使之满足最大堆,n为数组a的元素个数
{
int i, j, flag;
DataType temp;
i = h;
j = a*i + 1;
temp = a[i];
flag = 0;
//沿左右孩子结点中值较大者重复向下筛选
while(j<n && flag != 1)
{
//寻找左右孩子结点中的较大者,j为其下标
if(j < n-1 && a[j].key < a[j+1].key)
j++;
if(temp.key > a[j.key]) //a[i].key>a[j].key
flag = 1; //标记结束筛选条件
else //否则把a[i]上移
{
a[i] = a[j];
i = j;
j = a*i + 1;
}
}
a[i] = temp; //把最初的a[i]赋予最后的a[j]
}
@2.创建最大堆算法:
void InitCreateHeap (DataType a[], int n)
//把数组元素a[0]~a[n-1]初始化创建为最大堆
{
int i;
for(i = (n-2)/2; i >= 0; i--)
CreateHeap(a,n,i);
}
@3.堆排序算法
void HeapSort (DataType a[],int n)
//用堆排序法对数组元素a[0]~a[n-1]进行排序
{
int i;
DataType temp;
InitCreateHeap(a,n); //初始化创建最大堆
for(i = n-1;i > 0;i--) //当前最大堆个数每次递减1
{
//把堆顶a[0]元素和当前最大堆的最后一个数据元素交换
temp = a[0];
a[0] = a[i];
a[i] = temp;
CreateHeap(a,i,0); // 调整根节点满足最大堆
//此时子二叉树根节点下标为0,子二叉树结点个数为i
}
}
三、交换排序
1、冒泡排序
【冒泡排序的基本思想】设数组a中存放了n个数据元素,循环进行n-1次下列排序过程:
第一次,依次比较相邻两个数据元素a[i].key 和 a[i+1].key(i =0, 1, 2, ...,n-2).若为逆序,即a[i].key > a[i+1].key,
则交换两个数据元素,否则不交换,这样数值最大的数据元素将被放置在a[n-1]中;第二次,数据元素个数减1,
即数据元素个数为n-1,操作方法和第一次的类似,这样整个n个数据元素集合中次小的数据元素将被放置在a[1],
n为数组a的元素个数中,a[0]中放置了最小的数据元素。
冒泡排序算法:
void BubbleSort (DataType a[], int n)
//用冒泡排序法对数组元素a[0]~a[n-1]进行排序
{
int i, j, flag = 1;
DataType temp;
for(i = 1;i < n && flag == 1;i++)
{
flag = 0;
for(j = 0lj < n-i;j++)
{
if(a[j].key > a[j+1].key)
{
falg = 1;
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
}
2、快速排序
【快速排序算法的基本思想】设数组a中存放了n个数据元素,low为数组的低端下标,high为数组的高端下标,从数组
a中任取一个元素(通常取a[low])作为标准,调整数组a中各个元素的位置,使排在标准元素前面的元素的关键字均小于
标准元素的关键字,排在标准元素后面的元素关键字均大于或等于标准元素的关键字。递归算法的结束条件为high<=low,
即上界下标小于或等于下界下标。
快速排序算法:
void QuickSort(DataType a[], int low, int high)
//对数组元素a[low]~a[high]进行快速排序
{
int i = low, j = high;
DataType temp = a[low];
while(i < j)
{
while(i < j && temp.key <= a[j].key) //在数组的右端扫描
j--;
if(i < j)
{
a[i] = a[j];
i++;
}
while(i < j && a[i].key temp.key) //在数组左端扫描
i++;
if(i < j)
{
a[j] = a[i];
j--;
}
}
a[i] = temp;
if(low < i) //对左端子集合进行递归
QuickSort(a, low, i-1);
if(i < high) //对右端子集合进行递归
QuickSort(a, j+1,high);
}
四、归并排序
【归并排序的基本思想】设数组a存放了n个数据元素,初始时把它们看成n个长度为1的有序子数组,然后从第一个有序子数组开始,
把相邻的有序子数组两两合并,得到n/2(取整)个长度为2的新的有序子数组(当n为奇数时,最后一个新的有序子数组的长度为1)。
对这些新的有序子数组再进行两两归并。重复操作,直到得到一个长度为n的有序数组为止。
一次归并排序算法:
void Merge(DataType a[], int n, DataType swap[], int k)
//k为有序子数组的长度,一次归并排序后的有序子序列存于数组swap中
{
int m = 0, u1, l2, i, j, u2;
int l1 = 0; //第一个有序子数组下界为0
while(ll+k <= n-1)
{
l2 = l1 + k; //计算第二个有序子数组下界
u1 = l2 - 1; //计算第一个有序子数组上界
u2 = (l2+k-1 <= n-1)? l2+k-1: n-1 //计算第二个有序子数组上界
//两个有序子数组合并
for(i = l1, j = l2; i <= u1 && j <= u2; m++)
{
if(a[i].key <= a[j].key)
{
swap[m] = a[i];
i++;
}
else
{
swap[m] = a[j];
j++;
}
}
//子数组2已归并完,将子数组1中剩余的元素存放到数组swap中
while(i < u1)
{
swap[m] = a[i];
m++;
i++;
}
//子数组1已归并完,将子数组2中剩余的元素存放到数组swap中
while(j <= u2)
{
swap[m] = a[j];
m++;
j++;
}
l1 = u2 + 1;
}
//将原始数组中只够一组的数据元素顺序存放到数组swap中
for(i = l1; i < n; i++,m++)
swap[m] = a[i];
}
归并排序算法:
void MergeSort(DataType a[], int n)
{
int i , k = 1; //归并长度从1开始
DataType *swap;
swap = (DataType *)malloc(sizeof(DataType)*n); //申请动态数组空间
while(k < n)
{
Merge(a, n, swap, k); //调用归并函数Merge(a, n, swap, k)
for(i = 0;i < n; i++)
a[i] = swap[i]; //将元素从临时数组swap放回数组a中
k = 2 * k; //归并长度加倍
}
free(swap); //释放动态数组空间
}
五、基数排序
【基数排序的基本思想】设待排序的数据元素关键字是m位d进制整数(不足m位的关键字在高位补0),
设置d个桶,令其编号为0,1,2...,d-1。首先按关键字最低位的数值依次把各数据元素放到相应的桶中,
然后按照桶号从小到大和进入桶中数据元素的先后次序收集分配在各桶中的数据元素,这样就形成了数据元素集合的
一个新的排列,称这样的一次排序过程为一次基数排序;再对一次基数排序得到的数据元素序列按关键字次位的数值
依次把各数据元素放到相应的桶中,然后按照桶号从小到大和进入桶中数据元素的先后顺序收集分配在各桶中的数据元素;
重复上述操作,当完成了第m次基数排序后,就得到了排好序的数据元素序列。
基数排序算法:
#include "LQueue.h"
void RadixSort(DataType a[], int n, int m, int d)
//对数据元素a[0]~a[n-1]进行关键字为m位d进制整型数值的基数排序
//桶采用链式队列
{
int i, j, k, power = 1;
LQueue *tub;
//把d个队列定义为动态数组
tub = (LQueue *)malloc(sizeof(LQueue )* d);
for(i = 0;i < d; i++)
QueueInitiate(&tub[i]); //d个队列分别初始化
//进行m次放和收
for(i = 0; i < m; i++)
{
if(i == 0)
power = 1;
else
power = power * d;
//将数据元素按关键字第k位 的数值放到相应的队列中
for(j = 0; j < n; j++)
{
k = a[j].key / power - (a[j].key / (power * d)) * d; //计算k
QueueAppend(&tub[k], a[j]); //把a[j]放入第k个队列中
}
//顺序回收各队列中的数据元素至数组a中
k = 0;
for(j = 0; j < d; j++)
while(QueueNotEmpty(tub[j]) != 0)
{
QueueDelete(&tub[j], &a[k]); //从各队列中回收
k++;
}
}
}
著名的八大排序
最新推荐文章于 2022-02-19 19:17:30 发布