排序的基本概念
插入排序
直接插入排序
void D_Insert(RecordType R[], int n)
{
// 愚蠢的做法:
// 不需要每次将fast的元素和已经排好序的序列从0开始
// 比较,只需要将其和最大的元素进行比较
/*int slow = 0, fast = 1;
for(fast=1;fast<n;fast++)
{
for (int i = 0; i <= slow; i++)
{
if (R[i].key >= R[fast].key)
{
int Icur = i;
RecordType Rcur = R[fast];
for (i = fast; i > Icur; i--)
R[i] = R[i - 1];
R[Icur] = Rcur;
}
}
slow++;
}*/
for (int i = 1; i < n; i++)
{
if (R[i].key < R[i - 1].key)
{// 需要将R[i]插入到有序序列R[0]~R[i-1]中
RecordType cur = R[i];
int j;
for(j = i-1;j>=0;j--)
{
R[j + 1] = R[j];
if (cur.key > R[j].key)
break;
}
if (j < 0)
R[0] = cur;
else
R[j] = cur;
}
}
}
- 设置监视哨
折半插入排序
// 折半插入排序
void B_Insert(RecordType R[], int n)
{
for (int i = 1; i < n; i++)
{
if (R[i].key < R[i - 1].key)
{// 需要将R[i]插入到有序序列R[0]~R[i-1]中
RecordType cur = R[i];
int low = 0, high = i - 1;
// 寻找插入位置
while (low < high)
{
int mid = (low + high) / 2;
if (R[mid].key > cur.key)
high = mid - 1;
else
low = mid + 1;
}
// high+1为插入位置
for (int j = i - 1; j >= high + 1; j--)
R[j + 1] = R[j];
R[high + 1] = cur;
}
}
}
希尔排序
交换排序
冒泡排序
// 交换排序
void BubbleSort(RecordType R[], int m)
{
int swap = 0;
for (int i = 0; i < m; i++)
{
swap = 0;
for (int j = 0; j < m - i - 1; j++)
{
if (R[j].key > R[j + 1].key)
{
swap = 1;
RecordType tmp = R[j];
R[j] = R[j + 1];
R[j + 1] = tmp;
}
}
if (!swap)
break;
}
}
双向冒泡排序
void DBubbleSort(RecordType R[], int m)
{
int swap = 0;
for (int i = 0; i < m; i++)
{
// 从左到右排序
swap = 0;
for (int j = 0; j < m - i - 1; j++)
{
if (R[j].key > R[j + 1].key)
{
swap = 1;
RecordType tmp = R[j];
R[j] = R[j + 1];
R[j + 1] = tmp;
}
}
if (!swap)
break;
// 从右到左排序
swap = 0;
for (int j = m-1; j >i; j--)
{
if (R[j].key < R[j - 1].key)
{
swap = 1;
RecordType tmp = R[j];
R[j] = R[j - 1];
R[j - 1] = tmp;
}
}
if (!swap)
break;
}
}
快速排序
int Partition(RecordType R[], int i, int j) // 划分算法
{
// 对R[i]-R[j],以R[i]为基准记录进行划分,并返回R[i]在划分后的放置位置
int left = i ;
int right = j-1;
RecordType par = R[i];
while (left < right)
{
// 先在右边找到小于par的元素
while (left < right && R[right].key >= par.key)
right--;
if(left < right)
R[left++] = R[right];
//在左边找到大于par的元素
while (left < right && R[left].key <= par.key)
left++;
if (left < right)
R[right--] = R[left];
}
R[left] = par;
return left;
}
void QuickSort(RecordType R[], int s, int t) // 快速排序
{
int i;
if (s < t)
{
i = Partition(R, s, t);
QuickSort(R, s, i); // 注意以后所有的算法按照STL的标准区间都是左闭右开
QuickSort(R, i+1, t);
}
}
选择排序
直接选择排序
void SelectSort(RecordType R[], int n)
{
int Imin;
for (int j =0; j < n; j++)
{
Imin = j;
// 找出最小的元素
for (int i = j; i < n ; i++)
{
if (R[Imin].key > R[i].key)
Imin = i;
}
// 将最小元素依次放在前面
RecordType tmp = R[Imin];
R[Imin] = R[j];
R[j] = tmp;
}
}
双向直接选择排序
void DSelectSort(RecordType R[], int n)
{
int Imin,Imax;
for (int j = 0; j < n; j++)
{
Imin = j;
// 找出最小的元素
for (int i = j; i < n; i++)
{
if (R[Imin].key > R[i].key)
Imin = i;
}
// 将最小元素依次放在前面
RecordType tmp = R[Imin];
R[Imin] = R[j];
R[j] = tmp;
Imax = n - 1 - j;
// 找出最大的元素
for (int i = n-1-j; i > j; i--)
{
if (R[Imax].key < R[i].key)
Imax = i;
}
// 将最大元素依次放在后面
tmp = R[Imax];
R[Imax] = R[n - 1 - j];
R[n - 1 - j] = tmp;
}
}
堆排序
- 大顶堆
// 注意:
// 1. 当节点的索引号从0开始时,最后的非叶子节点的索引号为:n/2-1
// 2. i的左孩子为i*2+1,右孩子为i*2+2
// 用于创建初始堆及重新调整堆
void HeapAdjust(RecordType R[], int low, int high) //基于大根堆的堆排序
{ // R[low]~R[high]除R[s]外均满足堆定义,只将R[s]为根的完全二叉树调整为堆
int i, j;
i = low;// 调整首先从根节点开始
RecordType tmp = R[low];// 保存根节点的值
// 注意:对于从0开始的索引,左孩子的节点是2*i+1
for (j = 2 * i + 1; j < high; j = 2*j+1) //沿关键字较大的孩子向下调整,先假定为左孩子
{
if (j +1<high&& R[j].key < R[j + 1].key)
j += 1; // 若右孩子集节点的关键字大则沿右孩子向下调整
if (tmp.key >= R[j].key) break;// 即R[s]关键字已大于R[j]满足堆定义,不在进行向下调整
R[i] = R[j]; //将关键字大的孩子节点R[j]调整至双亲节点R[i]
i = j; // 定位于孩子节点继续向下调整
}
R[i] = tmp; // 把根节点放在树中合适的位置
}
// 创建大顶堆的函数
void HeapCreate(RecordType R[], int n)// 对R[1]~R[n]这n个记录进行堆排序
{
// 将 0~n/2-1的非叶子节点都进行操作
for (int i = n / 2 - 1; i >= 0; i--) // 从后向前调整所有非叶子节点为根的子树,使之成为大顶堆
HeapAdjust(R, i, n);
}
// 采用堆排序函数堆顺序表进行升序排列
void HeapSort(RecordType R[], int n)
{
int i;
RecordType tmp;
HeapCreate(R, n); // 创建初始大顶堆
for (i = n - 1 ; i > 0; i--) // 控制堆排序共进行n-1趟
{ // 将堆顶元素与待排范围的最后一个元素进行交换
tmp = R[0];
R[0] = R[i];
R[i] = tmp;
HeapAdjust(R, 0, i); // 将待排序的前i-1个元素重新调整为堆
}
}
归并排序
递归版
void Merge(RecordType R[], RecordType R1[], int s, int m, int n) // 一趟二路归并排序
{ // 将有序表R[s]~R[m]及R[m+1]~R[t]合并为R1[s]~R1[t]
int left = s, right = m ,k = s;
while (left < m && right < n)
{
if (R[left].key <= R[right].key)
R1[k++] = R[left++];
else
R1[k++] = R[right++];
}
while(left<m)
R1[k++] = R[left++];
while(right<n)
R1[k++] = R[right++];
}
void MSort(RecordType R[], RecordType R1[], int s, int t)
{ // 将无序表R[s]~R[t]归并到一个有序表R1[s]~R1[t] 注意区间是左闭右开
int m;
RecordType R2[8];
// 注意下标是从0开始的,且所有的区间都是左闭右开
if (t - s == 1) { // 当区间长度小于等于1时,无需排序
R1[s] = R[s];
}
else {
m = (s + t) / 2;
MSort(R,R2,s,m);// 将前半个无序表R[s]~R[m]归并到有序表R2[s]~R2[m]
MSort(R,R2,m,t);// 将后半个无序表R2[m+1]~R2[t]归并到有序表R2[m+1]~R2[t]
Merge(R2,R1,s,m,t); // 将有序表R2[s]~R2[m]和R2[m+1]~R2[t]归并到R1[s]~R1[t]
}
}
非递归版
基数排序
多关键字排序
链式基数排序
外排序
内排序方法讨论
提高效率
各种内排序方法比较