内部排序汇总
插入排序
直接插入排序
/* 直接插入排序 */
void insertSort(int a[], int n)
{
int i,j;
for (i=2;i<=n;i++) // 依次将a[i]插入到前面已排序序列
{
if (a[i]<a[i-1]) // 若a[i]小于其前驱,才需将a[i]插入有序表
{
a[0]=a[i]; // 复制为哨兵
for (j=i-1;a[0]<a[j];--j) // 从后往前查找插入位置
{
a[j+1]=a[j]; // 向后挪位
}
a[j+1]=a[0]; // 复制到插入位置
}
}
}
希尔排序
直接插入排序的时间复杂度为O(n2),但若待排序序列为正序时,其时间效率可提高至O(n)。希尔排序从以下两点分析出发对直接插入排序进行改进:
- 由于直接插入排序算法简单,则在n值很小时效率也比较高;
- 若待排序序列按关键字“基本有序”时,直接插入排序的效率可大大提高。
/* 希尔排序 */
void shellSort(int a[], int n)
{
// 对顺序表作希尔插入排序,本算法和直接插入排序相比,做了一下修改:
// 1> 前后记录位置的增量为dk,不是1
// 2> a[0]只是暂存单元,不是哨兵,当j<0时,插入位置已到
int dk,i,j;
for (dk=n/2;dk>=1;dk=dk/2) // 步长变化
{
for (i=dk+1;i<=n;i++)
{
if (a[i]<a[i-dk]) // 需将a[i]插入到有序增量子表
{
a[0]=a[i]; // 暂存在a[0]
for (j=i-dk;j>0&&a[0]<a[j];j-=dk)
{
a[j+dk]=a[j]; // 记录后移,查找插入的位置
}
a[j+dk]=a[0]; // 插入
}
}
}
}
交换排序
冒泡排序
/* 冒泡排序 */
void bubbleSort(int a[], int n)
{
int i,j;
for (i=0;i<n-1;i++) // 共有n-1趟排序
{
bool flag=false; // 表示本趟冒泡是否发生交换的标志
for (j=0;j<n-i-1;j++) // 一次冒泡过程
{
if (a[j]>a[j+1])
{
swap(a[j],a[j+1]);
flag=true;
}
}
if (flag==false)
{
break; // 本趟遍历后没有发生交换,说明表已经有序
}
}
}
快速排序
参考之前文章:快速排序
// 一趟快速排序,划分
int partition(int a[],int low,int high)
{
int i=low,j=high;
int x = a[i];
while (i!=j)
{
while (a[j]>=x && i<j) j—;
if (i<j) { a[i]=a[j]; i++; }
while (a[i]<=x && i<j) i++;
if (i<j) { a[j]=a[i]; j—; }
}
a[i]=x;
return i;
}
/* 快速排序 */
void quickSort(int a[],int low,int high)
{
if (low<high)
{
int k = partition(a,low,high);
quickSort(a,low,k-1);
quickSort(a,k+1,high);
}
}
选择排序
简单选择排序
/* 简单选择排序 */
void selectSort(int a[], int n)
{
int i,j,min;
for (i=0;i<n-1;i++) // 共进行n-1趟
{
min=i; // 记录最小元素位置
for (j=i+1;j<n;j++) // 在a[i...n-1]中选择最小的元素
{
if (a[j]<a[min])
{
min=j; // 更新最小元素位置
}
if (min!=i)
{
swap(a[i],a[min]); // 最小元素与第i个位置交换
}
}
}
}
堆排序
参考之前的文章:堆排序
/* 向下调整,即筛选 */
void adjustDown(int a[], int start, int n)
{
// 根结点编号为1,对第start个元素进行调整
a[0]=a[start]; // a[0]暂存
for (int i=2*start;i<=n;i*=2) // 沿较大的子结点向下筛选
{
if (i<n&&a[i]<a[i+1])
{
i++; // 取较大的子结点的下标
}
if (a[0]>=a[i])
{
break; // 筛选结束
}
else
{
a[start]=a[i]; // 将a[i]调整到双亲结点上
start=i; // 修改start,以便继续向下筛选
}
}
a[start]=a[0]; // 被筛选结点的值放入最终位置
}
/* 堆排序 */
void heapSort(int a[], int n)
{
for (int i=n/2;i>0;i--) // 1> 初始建堆,从i=n/2 --> 1,反复向下调整
{
adjustDown(a,i,n);
}
for (int j=n;j>1;j--) // 2> n-1趟的交换和建堆过程
{
swap(a[j],a[1]); // 输出堆顶元素(和堆底元素交换)
adjustDown(a,1,j-1); // 把剩余的j-1个元素整理成堆
}
}
二路归并排序
参考之前的文章:二路归并排序
// 一趟归并排序算法
int b[N];
void merge(int a[],int left,int mid,int right)
{
// 表a的两段a[left..mid]和a[mid+1..right]各自有序,将它们合并成一个有序表
for (int m=left;m<=right;m++)
b[m] = a[m]; // 将a中所有元素复制到b中
for (int i=left,j=mid+1,k=i;i<=mid&&j<=right;k++)
{
if(b[i]<=b[j]) // 比较b的左右两段中的元素
a[k]=b[i++]; // 将较小值复制到a中
else
a[k]=b[j++];
}
while (i<=mid) a[k++]=b[i++]; // 若第一个表为检测完,复制
while (j<=right) a[k++]=b[j++]; // 若第二个表为检测完,复制
// 最后两个while循环只有一个会执行
}
/* 二路归并排序 */
void mergeSort(int a[],int left,int right)
{
if (left < right)
{
int mid = (left+right)/2; // 从中间划分两个子序列
mergeSort(a,left,mid); // 对左侧子序列进行递归排序
mergeSort(a,mid+1,right); // 对右侧子序列进行递归排序
merge(a,left,mid,right); // 归并
}
}








浙公网安备 33010602011771号