1. 直接选择排序法
基本思想:每一趟(第i趟, i = 0, 1, 2, ......n-1)在后面n-i个待排序记录中选出关键字最小的记录,作为有序记录序列的第i个记录。直到第n-2趟完,待排记录只剩下一个,不完再选了!
//直接选择排序法
void SelectionSort(int * pArry, int iLen)
{
int i, j;
int k;
int temp;
for (i = 0; i < iLen; i++) // 循环趟次
{
k = i;
for (j = i + 1; j < iLen; j++)
{
if (pArry[j] < pArry[k])
{
k = j; // 每趟循环查找序列中关键字最小的记录,保存其索引值
}
}
if ( k != i) //如果关键字最小的记录的索引值不等于子序列第一个记录的索引
{ //则将换两记录,使序列中关键字最小的记录排在序列第一位,然后对子序列重复上述步骤
temp = pArry[i];
pArry[i] = pArry[k];
pArry[k] = temp;
}
}
}
直接排序算法的时间复杂度为O(n ^2), 且是一种不稳定的排序方法!记录的移动次数与元素序列的初始排列有关。
2. 堆排序
堆的定义:n个元素的序列k1,k2,k3,......kn当且仅当满足下关系时,称之为堆。
若将序列对应的一维数组看成是一个完全二叉树,则堆 的含义表明,完全二叉树所有非终端结点的均值不大于(或不小于)其左、右孩子的结点的值。由此,若序列k1,k2.....kn是堆,则堆顶元素(完全二叉树的根)必为序列中n个元素的最小值(或最大值)。
若在输出堆顶的最小值之后,使得剩余n-1个元素的序列重建成一个堆,则得到的n个元素的次小值。如此反复执行,便能得到一个有序序列,这个过程称之为堆排序。堆排序的需解决的核心问题是:1)如何由初始无序序列构建堆,2)在输出堆顶元素之后怎么调整使剩下的元素构成新的堆。
//建立最大堆
void HeapAdjust(int * pArry, int start, int len)
{
int i = start, j = 2 * i + 1; //j是i的左孩子
int temp= pArry[i]; //暂存子树根节点
while (j <= len) //检查是否到最后位置
{
if (j < len && pArry[j] < pArry[j + 1]) //让j指向左右孩子中较大者
{
++j;
}
if (temp >= pArry[j]) //temp的排序码大则不做调整,否则孩子中的较大者上移
{
break;
}
else
{
pArry[i] = pArry[j];
i = j; //i下降到子女位置
j = 2 * j + 1;
}
}
pArry[i] = temp; //temp中暂存元素放到合适的位置
}
void HeapSort(int * pArry, int len)
{
int i;
for (i = len / 2; i >= 0; --i) //将表转换为堆
{
HeapAdjust(pArry, i, len);
}
for (i = len; i >= 0; i--) //对表进行排序
{
swap(pArry[0], pArry[i]); //交换,根节点(表中的最大值)排在了最后
HeapAdjust(pArry, 0, i - 1); //重建最大堆
}
}
堆排序算法对记录数较少的文件并不提倡,但对n较大的文件还是很有效的,因为其运行时间主要消耗在建初始堆和调整建立新堆的反复筛选上。堆排序的时间复杂度为O(nlog2(n)), 且是不稳定的排序算法。