数据结构排序算法
一,排序基本概念
算法的稳定性
算法的稳定性与算法的性能无关
内部排序
元素存放在在内存中的排序
外部排序
元素不断在内外存之间移动的排序
二,插入排序
- 直接插入排序
适用于顺序存储和链式存储
1.1 源代码:
void InsertSort(Elemtype A[],int n){
int i,j;
for(i=2,i<n;i++)
{
if(A[i].key<A[i-1].key)//由循环条件知,该算法是稳定的
{
A[0]=A[i]; //A[0]起哨兵作用,防止数组越界,提高效率
for(j=i-1;A[0].key<A[j].key;--j)//后往前查找插入的位置
{
A[j+1]=A[j];//向后挪位
}
A[j+1]=A[0];//复制到插入位置
}//if
}//for
}//InserSort
1.2 性能分析
空间效率:O(1)
时间效率:
- 最好情况(已经有序) O(n)
- 最坏情况 (逆序)O(n^2)
- 平均情况 O(n^2)
2 折半插入排序
适用于顺序存储
2.1 源代码:
void InsertSort(ElemType A[],int n)
{
int i,j,low,high,mid;
for(i=2;i<n;i++)
{
A[0]=A[i];
low=1;high=i-1;//问:为什么不是high=i?答:折半查找的是该点前适合插入的
//位置,当然不能包括自己
while(low<=high)//算法稳定
{
mid=(low+high)/2;
if(A[0].key<A[mid].key)
high = mid-1;//查找左边
else
low = mid + 1//查找右边
}//while
for(j=i-1;j>=high+1;--j)
A[j+1]=A[j];//元素后移,最后选择的元素的位置在high+1位置上
A[high+1]=A[0];//插入操作,问:为什么是A[high+1]=A[0];
}
}
2.2 性能分析
比较次数为O(nlog2^n)
时间复杂度O(n^2)
3 希尔排序
不稳定且仅适用于顺序存储
3.1 源代码:
void ShellSort(ElemType A[],int n){
//主要修改部分,前后记录位置的增量是 dk ,不是 1
//r[0]只是暂存单元不是哨兵,当j<=0时,插入位置已到
for(dk = n / 2;dk>=1;dk = dk / 2)//步长最后要为1
for(i=dk+1;i<=n;i++)//i从dk+1开始有利于判断数组范围
{
if(A[i].key<A[i-1].key)//跟直接插入,折半插入处理方式一样
{
A[0]=A[i];
for(j=i-dk;i>0&&A[0].key<A[j].key;j-=dk)//相应步长的元素比较
{
A[j+dk]=A[j];//元素处理和其他插入排序类似
}//for
A[j+dk]=A[0];
}//if
}//for
}
3.2 性能分析
空间复杂度 O(1)
时间复杂度 O(n^2)
三,交换排序
1 冒泡排序
1.1 源代码
void BubbleSort(ElemType A[],int n)
{
fir(i=0;i<n-1;i++)
{
flag=false;//冒泡是否交换的标志
for(j=n-1;j>i;j--)//一趟冒泡标志,从后面往前冒泡
{
if(A[j-1].key>A[j].key)
{
swap(A[j-1],A[j]);
flag=true;//冒泡标记
}
}
if(flag==false)
return ;
}
1.2性能分析
空间效率 O(1)
时间复杂度 O(n^2)
- 快速排序
2.1 源代码
//快速排序,不稳定,
void QuickSort(ElemType A[],int low,int high){
if(low<high)
{
//Partition()是划分操作
int pivotpos = Partition(A,low,high);
QuickSort(A,low,pivotpos-1);
QuickSort(A,pivotpos+1,high);
}
}
//一趟排序过程
int Partition(ELemType A[],int low,int high)
{
ElemType pivot = A[low];
while(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;
}
2.2性能分析
快速排序算法是内部排序算法中平均性能最优的
空间效率
- 最坏情况O(n)
- 最好情况O(nlog2^n)
时间效率
- 最好情况O(nlog2^n)
- 最坏情况O(n^2)
四,选择排序
1 简单选择排序
1.1 源代码
void SelectSort(ElemType A[],int n){
for(i=0;i<n-1;i++)
{
min = i;
for(j=i+1;j<n;j++)
if(A[j]<A[min]) min=j;
if(min!=i) swap(A[i],A[min]);
}
}
1.2 性能分析
空间效率 O(1)
时间效率O(n^2)
2.堆排序
1.1 源代码
//大根堆
void BuildMaxHeap(ELemType A[],int len){
for(int i=len/2;i>0;i--)
AdjustDown(A,i,len);
}
void AdjustDown(ElemType A[],int k,int len){
A[0]=A[k];
for(i=2*k;i<=len;i*=2)
{
if(i<len&&a[i]<A[i+1])
i++;
if(A[0]>=A[i]) break;
else{
A[k]=A[i];
k=i;
}
}//for
A[k]=A[0];
}
//堆排序
void HeapSort(ElemType A[],int len){
BuildMaxHeap(A,len);
for(i=len;i>1;i--)
swap(A[i],A[1]);
AdjustDown(A,1,i-1);
}//for
}
//向上调整堆
void AdjustUp(ElemType A[],int k)
{
A[0]=A[k];
int i=k/2;
while(i>0&&A[i]<A[0]){
A[k]=A[i];
k=i;
i=k/2;
}//while
A[k]=A[0];
}
1.2 性能分析
空间效率 O(1)
时间效率 O(nlog2^n)
五,归并排序
1.1 源代码
稳定
ElemType *B=(ElemType *) malloc((n+1)*sizeof(ElemType));
void Merge(ElemType A[],int low,int mid,int high){
for(int k=low;k<=high;;k++)
B[k]=A[k];
for(i=low,j=mid+1,k=i;i<=mid&&j<=high;k++){
if(B[i]<=B[j])
A[k]=B[i++];
else
A[k]=B[j++];
}//for
while(j<=mid) A[k++]=B[j++];
while(j<=high) A[k++]=B[j++];
}
//合并
void MergeSort(ElemType 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);
}//if
}
1.2 性能分析
空间效率 O(n)
时间效率 O(nlog2^n)
六,基数排序
性能分析
稳定
空间效率 O® r个队列
时间效率 O(d(n+r))
七,归纳总结