数据结构学完了,总结一下排序。没有那种排序永远是最优的,各有千秋吧。
//插入排序
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int * insert_sort(int a[], int n)//直接插入排序
{
int i,j;
for(i = 2; i <= n; i++)
{
if(a[i-1] > a[i])
{
a[0] = a[i]; //复制为监视哨
a[i] = a[i-1]; //将a[i-1]后移
for(j = i-2; a[j] > a[0]; j--)
a[j+1] = a[j];//将j+1与i-2之间的数向后移,j满足a[j+1] > a[0]而a[j] < a[0];
a[j+1] = a[0];//将待插入的a[i]插入a[j+1]处
}
}
return a;
}
//折半查找
int binsearch(int a[], int low, int high,int num)
{
while(low <= high)
{
int m = (low+high)/2;
if(a[m] > num)
high = m-1;
else if(a[m] < num)
low = m+1;
}
return low;
}
int * biInsertion_sort(int a[], int n)//折半插入排序
{
int i,j;
for(i = 2; i <= n; i++)
{
if(a[i-1] > a[i])
{
a[0] = a[i];
int low = binsearch(a,1,i-1,a[i]);//通过折半查找找到a[i]插入的位置为a[low];
for(j = i-1; j >= low; j--)
a[j+1] = a[j];
a[low] = a[0];
}
}
return a;
}
int * BubbleSort(int a[], int n)//起泡排序
{
int i = n,j;
int lastexchang;
while(i > 1)
{
lastexchang = 1;//初始化最后一次交换位置
for(j = 1; j < i; j++)
{
if(a[j] > a[j+1])
{
swap(a[j],a[j+1]);
lastexchang = j;//更新最后一次交换位置
}
}
i = lastexchang;//lastexchang~n的关键字已经有序,下次从1~lastexchang-1 排序
}
return a;
}
int main()
{
int a[110];
int n;
scanf("%d",&n);
for(int i = 1; i <= n; i++)
scanf("%d",&a[i]);
insert_sort(a,n);//对长度为n的数组从小到大直接插入排序
biInsertion_sort(a,n);//对长度为n的数组从小到大折半插入排序
BubbleSort(a,n);//对长度为n的数组从小到大起泡排序
for(int i = 1; i <= n; i++)
printf("%d ",a[i]);
return 0;
}
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
//调整堆,从i节点开始从上往下调整,n为节点总数
void MaxHeapFixDown(int *a, int i, int n)
{
int j = 2*i+1;//i节点的子节点
int tmp = a[i];
while(j < n)
{
if(j + 1 < n && a[j+1] > a[j])//在节点i的左右孩子中找最大的
j++;
if(tmp >= a[j])//如果tmp 均大于其左右孩子,说明已是合法堆
break;
//否则就继续向下调整
a[i] = a[j];
i = j;
j = 2*i+1;
}
a[i] = tmp;
}
//建立最大堆
void MakeMaxHeap(int *a, int n)
{
//对叶子节点来说,它们已是合法的最大堆了,所以只需从 n/2-1 开始向下调整就行了
for(int i = n/2-1; i >= 0; i--)
{
MaxHeapFixDown(a,i,n);
}
}
//堆排序,先建立一个最大堆,那么a[0]肯定是节点中最大的,第一次将a[0]与a[n-1]交换,
//再对a[0~n-2]调整堆,第二次将a[0]与a[n-2]交换,再对a[0~n-3]调整堆,重复这样的操作,
//直到a[0]与a[1]交换,最后得到一个递增的有序序列。
void MaxHeapSort(int * a, int n)
{
MakeMaxHeap(a,n);
for(int i = n-1; i >= 1; i--)
{
swap(a[i],a[0]);
MaxHeapFixDown(a,0,i);
}
}
int main()
{
int n,a[110];
scanf("%d",&n);
for(int i = 0; i < n; i++)
scanf("%d",&a[i]);
MaxHeapSort(a,n);
for(int i = 0; i < n; i++)
printf("%d ",a[i]);
printf("\n");
return 0;
}
//归并排序
//划分问题,把序列分成元素个数尽量相等的两半
//递归求解,把两半元素分别排序
//合并问题,把两个有序表合并成一个
#include<stdio.h>
#include<string.h>
void merge_sort(int *a, int x, int y, int *t)
{
if(y - x > 1)
{
int m = x + (y-x)/2;//划分
int p = x, q = m, i = x;
merge_sort(a,x,m,t);//递归求解
merge_sort(a,m,y,t);//递归求解
while(p < m || q < y)
{
if(q >= y || (p < m && a[p] <= a[q]))
t[i++] = a[p++];//从左半数组复制到临时空间
else t[i++] = a[q++];//从右半数组复制到临时空间
}
for(int i = x; i < y; i++)
a[i] = t[i];//从辅助空间复制回a数组
}
}
int main()
{
int n;
int a[110];
scanf("%d",&n);
for(int i = 0; i < n; i++)
scanf("%d",&a[i]);
int * t = new int [n];//开辟辅助存储空间
merge_sort(a,0,n,t);
for(int i = 0; i < n; i++)
printf("%d ",a[i]);
return 0;
}
//快速排序的时间复杂度为O(nlogn)
//若待排记录的初始状态为按关键字有序时,快速排序将蜕化为起泡排序,其时间复杂度为O(n2)。
#include<stdio.h>
#include<string.h>
//一趟快速排序
int Partition(int a[], int low, int high)
{
int t = a[low];// 枢轴
while(low < high)
{
while(low < high && a[high] >= t)
high--;// 从右向左搜索
a[low] = a[high];
while(low < high && a[low] <= t)
low++;// 从左向右搜索
a[high] = a[low];
}
a[low] = t;
return low;
}
void Qsort(int a[],int s, int t)
{
int pivotloc;
if(s < t)// 长度大于1
{
pivotloc = Partition(a,s,t); // 对 a[s..t] 进行一次划分
Qsort(a,s,pivotloc-1); // 对低子序列递归排序,pivotloc是枢轴位置
Qsort(a,pivotloc+1,t);// 对高子序列递归排序
}
}
int main()
{
int a[110],n;
scanf("%d",&n);
for(int i = 0; i < n; i++)
scanf("%d",&a[i]);
Qsort(a,0,n-1);
for(int i = 0; i < n-1; i++)
printf("%d ",a[i]);
printf("%d\n",a[n-1]);
return 0;
}
时间性能分析:
1. 平均的时间性能:
基数排序时间复杂度为O(n);
归并排序,堆排序,快速排序的时间复杂度为Ο(nlogn);
直接插入排序、起泡排序和简单选择排序时间复杂度为 O(n2);
2. 当待排记录序列按关键字顺序有序时:
直接插入排序和起泡排序能达到O(n)的时间复杂度;
快速排序的时间性能蜕化为O(n2)
3. 简单选择排序、堆排序和归并排序的时间性能不随记录序列中关键字的分布而改变。
二、空间性能(指的是排序过程中所需的辅助空间大小):
1. 所有的简单排序方法(包括:直接插入、起泡和简单选择) 和堆排序的空间复杂度为O(1);
2. 快速排序为O(logn),为递归程序执行过程中,栈所需的辅助空间;
3. 归并排序所需辅助空间最多,其空间复杂度为 O(n);
4. 链式基数排序需附设队列首尾指针,则空间复杂度为 O(rd)。
三、排序方法的稳定性能:
1. 稳定的排序方法指的是,对于两个关键字相等的记录,它们在序列中的相对位置,在排序之前和经过排序之后,没有改变。
2 快速排序、堆排序和希尔排序是不稳定的排序方法。