- 时间复杂度
- 空间复杂度
- 稳定性
- 内部排序
- 外部排序
//直接插入排序
void InsertSort(int a[], int n)
{
int i, j, temp;
for(i=1;i<n;i++) //将各元素插入已排好序的序列中
{
if(a[i] < a[i-1]) //若A[i]关键字小于前驱
{
temp = a[i]; //用temp暂存A[i]
for(j=i-1;j>=0 && a[j] > temp;j--) //检查所有前面已排好序的元素
{
a[j+1]=a[j]; //所有大于temp的元素都向后挪位
}
a[j+1]=temp; //复制到插入位置
}
}
}
//直接插入排序(带哨兵)
void InsertSort(int a[], int n)
{
int i, j;
for(i=2;i<=n;i++) //依次将A[2]~A[n]插入到前面已排序序列
{
if(a[i] < a[i-1]) //若A[1]关键码小于其前驱,将A[i]插入有序表
{
a[0] = a[i]; //复制为哨兵,A[0]不存放元素
for(j=i-1;a[0] < a[j]; j--) //从后往前查找待插入位置
{
a[j+1] = a[j]; //向后挪位
}
a[j+1] = a[0]; //复制到插入位置
}
}
}
- 当 low > high 时折半查找停止,应将 [low, i - 1] 内的元素全部右移,并将 A[0] 复制到 low 所指位置
- 当 A[mid] = A[0] 时,为了保证算法的“稳定性”,应继续在 mid 所指位置右边寻找插入位置
//折半插入排序
void InsertSort2(int a[], int n)
{
int i, j ,low, mid, high;
for(i=2;i<=n;i++) //依次将a[2]~a[n]插入到前面的已排序序列
{
a[0]=a[i]; //将a[i]暂存到a[0]
low=1;high=i-1; //设置折半查找范围
while(low<=high) //折半查找(默认递增有序)
{
mid = (low+high)/2; //取中间点
if(a[mid] > a[0]) //查找左半子表
{
high = mid-1;
}
else //查找有半子表
{
low = mid+1;
}
for(j=i-1;j>=high+1;j--)
{
a[j+1]=a[j]; //统一后移元素,空出插入位置
}
a[high+1] = a[0]; //插入操作
}
}
}
#include <stdio.h>
void printstring(int a[], int n);//打印数组
void InsertSort(int a[], int n);//直接插入排序
void InsertSort1(int a[], int n);//直接插入排序(带哨兵)
void InsertSort2(int a[], int n);//折半插入排序
void main()
{
int a[10]={1,9,0,2,4,2,6,5,8,34};
int b[11]={-1,1,9,0,2,4,2,6,12,8,34};
InsertSort(a, 10);
InsertSort2(b, 11);
printstring(a,10);
printstring(b,11);
}
//打印数组
void printstring(int a[], int n)
{
int i;
for(i=0;i<n;i++)
{
printf("%d\t",a[i]);
}
printf("\n");
}
//直接插入排序
void InsertSort(int a[], int n)
{
int i, j, temp;
for(i=1;i<n;i++) //将各元素插入已排好序的序列中
{
if(a[i] < a[i-1]) //若A[i]关键字小于前驱
{
temp = a[i]; //用temp暂存A[i]
for(j=i-1;j>=0 && a[j] > temp;j--) //检查所有前面已排好序的元素
{
a[j+1]=a[j]; //所有大于temp的元素都向后挪位
}
a[j+1]=temp; //复制到插入位置
}
}
}
//直接插入排序(带哨兵)
void InsertSort1(int a[], int n)
{
int i, j;
for(i=2;i<=n;i++) //依次将A[2]~A[n]插入到前面已排序序列
{
if(a[i] < a[i-1]) //若A[1]关键码小于其前驱,将A[i]插入有序表
{
a[0] = a[i]; //复制为哨兵,A[0]不存放元素
for(j=i-1;a[0] < a[j]; j--) //从后往前查找待插入位置
{
a[j+1] = a[j]; //向后挪位
}
a[j+1] = a[0]; //复制到插入位置
}
}
}
//折半插入排序
void InsertSort2(int a[], int n)
{
int i, j ,low, mid, high;
for(i=2;i<=n;i++) //依次将a[2]~a[n]插入到前面的已排序序列
{
a[0]=a[i]; //将a[i]暂存到a[0]
low=1;high=i-1; //设置折半查找范围
while(low<=high) //折半查找(默认递增有序)
{
mid = (low+high)/2; //取中间点
if(a[mid] > a[0]) //查找左半子表
{
high = mid-1;
}
else //查找有半子表
{
low = mid+1;
}
for(j=i-1;j>=high+1;j--)
{
a[j+1]=a[j]; //统一后移元素,空出插入位置
}
a[high+1] = a[0]; //插入操作
}
}
}
- 希尔排序:先追求表中元素部分有序,再逐渐逼近全局有序
- 时间复杂度:和增量序列d,d2,d3…的选择有关,目前无法用数学手段证明确切的时间复杂度最坏时间复杂度为O(n^2),当n在某个范围内时,可达O(n^13)
- 适用性:仅适用于顺序表,不适用于链表
#include <stdio.h>
void printstring(int a[], int n);//打印数组
void Shellsort(int a[], int n);//希尔排序
void main()
{
int b[11]={-1,1,9,0,2,4,2,6,12,8,34};
Shellsort(b, 11);
printstring(b,11);
}
//打印数组
void printstring(int a[], int n)
{
int i;
for(i=0;i<n;i++)
{
printf("%d\t",a[i]);
}
printf("\n");
}
//希尔排序
void Shellsort(int a[], int n)
{
int i,j,d;
//a[0]只是暂存单元,不是哨兵,当j<=0时,插入位置已到
for(d=n/2;d>=1;d=d/2) //步长变化
{
for(i=d+1;i<=n;i++)
{
if(a[i] < a[i-d]) //需将a[i]插入有序增量子表
{
a[0] = a[i]; //暂存在a[0]中
for(j=i-d;j>0 && a[0]<a[j];j-=d)
{
a[j+d] = a[j]; //记录后移,查找插入的位置
}
a[j+d] = a[0]; //插入
}//if
}
}
}
知识回顾与重要考点
#include <stdio.h>
//交换两个元素的值
void swap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
void BubbleSort(int a[], int n)
{
int i,j;
for(i=0;i<n-1;i++)
{
int flag=0; //表示本趟冒泡是否发生交换的标志
for(j=n-1;j>i;j--) //一趟冒泡过程
{
if(a[j] < a[j-1]) //若为逆序
{
swap(&a[j-1], &a[j]); //交换
flag=1;
}
}
if(flag==0) //本趟遍历没有发生交换,说明表已经有序
return;
}
}
void main()
{
int a[10]={10,5,0,9,2,7,4,7,2,40};
BubbleSort(a,10);
for(int i=0;i<10;i++)
{
printf("%d\t",a[i]);
}
printf("\n");
}
知识回顾与重要考点
#include <stdio.h>
//用第一个元素将待排序序列划分成左右两个部分
int Partition(int a[], int low, int high)
{
int pivot=a[low]; //第一个元素作为枢轴
while(low < high) //用low、high搜索枢轴的最终位置
{
while(low < high && a[high] >= pivot) high--;
a[low] = a[high]; //比枢轴小的元素移到到左端
while(low < high && a[low] <= pivot) low++;
a[high] = a[low]; //比枢轴大的元素移到到右端
}
a[low] = pivot; //枢轴元素存放到最终位置
return low; //返回存放枢轴的最终位置
}
//快速排序
void QuickSort(int a[], int low, int high)
{
if(low < high) //递归跳出的条件
{
int pivotpos = Partition(a, low, high);//划分
QuickSort(a, low, pivotpos-1); //划分左子表
QuickSort(a, pivotpos+1, high); //划分右子表
}
}
void main()
{
int a[10]={10,29,0,1,23,45,8,4,2,1};
QuickSort(a, 0, 9);
for(int i=0;i<10;i++)
{
printf("%d\t",a[i]);
}
printf("\n");
}
选择排序:每一趟在待排序元素中选取关键字最小(或最大)的元素加入有序子序列
#include <stdio.h>
void printstring(int a[], int n);//打印数组
void SelectSort(int a[], int n);//简单选择排序
void main()
{
int b[11]={-1,1,9,0,2,4,2,6,12,8,34};
SelectSort(b, 11);
printstring(b,11);
}
//打印数组
void printstring(int a[], int n)
{
int i;
for(i=0;i<n;i++)
{
printf("%d\t",a[i]);
}
printf("\n");
}
//简单选择排序
void SelectSort(int a[], int n)
{
int i,j;
for(i=0;i<n-1;i++) //一共进行n-1趟
{
int min = i; //记录最小元素的位置
for(j=i+1;j<n;j++) //在a[i...n-1]中选择最小的元素
{
if(a[min] > a[j]) //更新最小元素的位置
{
min = j;
}
}
if(min != i) //交换元素位置,共移动元素3次
{
int temp = a[min];
a[min] = a[i];
a[i] = temp;
}
}
}
稳定性:不稳定
#include <stdio.h>
//将以k为根的子树调整为大根堆
void HeadAdjust(int a[],int k,int len)
{
a[0] = a[k]; //a[0]暂存子树的根结点
for(int i=2*k;i<=len;i*=2) //沿着key较大的子结点向下筛选
{
if(i<len&&a[i]<a[i+1]) //取得key较大的子结点的下标
{
i++;
}
if(a[0] >= a[i]) //筛选结果
{
break;
}
else
{
a[k] = a[i]; //将a[i]调整到双亲结点上
k = i; //修改k值,以便继续向下筛选
}
}
a[k] = a[0]; //被筛选结点的值放入最终位置
}
//建立大根堆
void BuildMaxHeap(int a[],int len)
{
for(int i=len/2;i>0;i--) //从后往前调整所有非终端结点
{
HeadAdjust(a,i,len);
}
}
//堆排序的完整逻辑
void HeapSort(int a[],int len)
{
BuildMaxHeap(a,len); //建立初始的堆
for(int i=len;i>1;i--) //n-1趟的交换和建堆过程
{
int temp = a[i]; //堆顶元素和堆底元素交换
a[i] = a[1];
a[1] = temp;
HeadAdjust(a,1,i-1); //把剩余的待排序元素整理成堆
}
}
void main()
{
int a[11]={0,10,29,0,1,23,45,8,4,2,1};
HeapSort(a, 10);
for(int i=0;i<11;i++)
{
printf("%d\t",a[i]);
}
printf("\n");
}
以小根堆为例:
对于小根堆,新元素放到表尾,与父节点对比,若新元素比父节点更小,则将二者互换。新元素就这样一路“上升”,直到无法继续上升为止
以小根堆为例:
被删除的元素用堆底元素替代,然后让该元素不断“下坠”,直到无法下坠为止
#include <stdio.h>
int b[11];
//a[low...mid]和a[mid+1...high]各自有序,将两个部分归并
void Merge(int a[],int low,int mid,int high)
{
int i,j,k;
for(k=low;k<=high;k++)
{
b[k] = a[k]; //将a中所有元素复制到b中
}
for(i=low,j=mid+1,k=i;i<=mid&&j<=high;k++)
{
if(b[i] <= b[j])
{
a[k] = b[i++]; //将最小值复制到a中
}
else
{
a[k] = b[j++];
}
}
while(i<=mid) a[k++] = b[i++];
while(j<=high) a[k++] = b[j++];
}
void MergeSort(int a[],int low,int high)
{
if(low<high)
{
int mid=(low+high)/2; //从中间划分
MergeSort(a,low,mid); //对左半部分归并排序
MergeSort(a,mid+1,high); //对右半部分归并排序
Merge(a,low,mid,high); //归并
}
}
void main()
{
int a[10]={10,2,1,9,6,7,5,0,3,2};
MergeSort(a,0,9);
for(int i=0;i<10;i++)
{
printf("%d\t",a[i]);
}
printf("\n");
}