稳定排序:通俗地讲就是能保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。在简单形式化一下,如果Ai = Aj, Ai原来在位置前,排序后Ai还是要在Aj位置前。
冒泡排序、插入排序、归并排序
不稳定排序:快速排序、选择排序
各个排序的稳定性分析见下载的一篇文章。
1.冒泡排序(Bubble Sort)
思想:借助“交换”进行排序的方法。
首先第一个和第二个比较,大的放后面,一次第二个和第三个比较,...一趟冒泡排序后,最大的放到最后一个位置上。在进行第二趟。。。
时间复杂度:O(n^2)
空间复杂度:
void bubblesort(int a[],int n)
{
int i,j;
for(i=0;i<n-1;i++)
for(j=0;j<n-i-1;j++)
if(a[j]>a[j+1])
{
int temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
- 改进后的冒泡排序: 防止重复排序, 有时候 某趟过后就排好了
设置标志flag,修改结束条件为:在一趟排序过程中没有进行过交换记录的操作。
void bubblesort(int a[],int n)
{
int flag,i,j;
flag=1;
for(i=0;i<n-1 && flag==1;i++)
{ flag=0;
for(j=0;j<n-i-1;j++)
if(a[j]>a[j+1])
{
int temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
flag=1;
}
}
}
2.快速排序(Quick Sort)
思想:分治思想,不断寻找一个序列的中点,然后对中点左右的序列递归的进行排序,直至全部序列排序完成。
以第一个元素为基准,借助交换,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录连续进行排序(递归),已达到整个序列的有序。
时间复杂度:O(nlogn)
空间复杂度:
适用于:顺序表线性结构或数组序列的排序,不适用于链表数据结构的排序。因为快排要不断进行交换操作,交换是一种随机的访问,链表不支持随机的访问。
#include <stdio.h>
void QuickSort(int *a,int low,int high);
int FindPos(int *a,int low,int high);
int main(void)
{
int a[6]={-2,1,0,5,4,3};
QuickSort(a,0,5); //第二个参数表示第一个元素的下标 第三个参数表示最后一个元素的下标
for (int i=0;i<6;++i)
printf("%d ",a[i]);
printf("\n");
return 0;
}
void QuickSort(int *a,int low,int high) //查找一定成功,不返回值
{
int pos;
if (low<high)
{
pos = FindPos(a,low,high); //找到数组a中从low开始到hign结束的第一个元素的位置
QuickSort(a,low,pos-1); //左边一半继续这样排
QuickSort(a,pos+1,high); //右边一半继续这样排
}
}
int FindPos(int *a,int low,int high) //一趟排序后找到分界点(书上为此种写法)
{
int val = a[low];
while(low<high)
{
while(low<high && a[high]>=val)
--high;
a[low]=a[high]; //注意是改变a[low]的值
while(low<high && a[low]<=val)
++low;
a[high]=a[low]; //注意改变a[high]的值
} //终止while循环后,low和high的值相等
a[low]=val; //最后
return low;//low可以改为 high
}
- 另一种FindPos()函数的不同。
#include <stdio.h>
#include <math.h>
void QuickSort(int *a,int low,int high);
int FindPos(int *a,int low,int high);
int main(void)
{
int a[6]={-2,1,9,5,-7,3};
QuickSort(a,0,5); //第二个参数表示第一个元素的下标 第三个参数表示最后一个元素的下标
for (int i=0;i<6;++i)
printf("%d ",a[i]);
printf("\n");
return 0;
}
void swap(int *p1,int *p2) //注意此函数形参为指针
{
int temp;
temp=*p1;
*p1=*p2;
*p2=temp;
}
void QuickSort(int *a,int low,int high) //查找一定成功,不返回值
{
int pos;
if (low<high)
{
pos = FindPos(a,low,high); //找到数组a中从low开始到hign结束的第一个元素的位置
QuickSort(a,low,pos-1); //左边一半继续这样排
QuickSort(a,pos+1,high); //右边一半继续这样排
}
}
int FindPos(int *a,int low,int high) //一趟排序后找到分界点(书上为此种写法)
{
int val = a[low];
while(low<high)
{
while(low<high && a[high]>=val)
--high;
swap(&a[low],&a[high]); //交换
while(low<high && a[low]<=val)
++low;
swap(&a[low],&a[high]); //交换
} //终止while循环后,low和high的值相等
return low;//low可以改为 high
}
3.插入排序
直接插入排序(straight insertion sort)
思想:将一个记录插入到已排好序的有序表中,从而得到一个新的、记录新增1的有序表。
整个排序过程为进行n-1趟插入,即:先将序列中的第一个记录看成是一个有序的子序列,然后从第二个记录起逐个进行插入,直至整个序列变成按关键字非递减有序序列为止。
时间复杂度:O(n^2)
空间复杂度:
//插入排序
//直接插入排序
//将一个数据插入到已经排好序的有序数据中,从而得到一个新的个数加 1 的有序数,此算法适用于少量数据的排序。
#include <iostream>
using namespace std;
void insertsort(int a[],int n)
{
int i,j,temp;
for(i=1;i<n;i++) //开始第0个排好,依次从第一个元素开始插入
{
temp=a[i];
j=i-1;
while(j>=0 && a[j]>temp) //依次与前面元素比较,若小于前面元素,则依次向右移动
{
a[j+1]=a[j];
j--;
} //直到遇到比前面某个元素大或者相等,则
a[j+1]=temp; //插入到这个元素后面
}
}
int main()
{
int a[6];
cout<<"请输入数组元素:";
for(int i=0;i<6;i++)
cin>>a[i];
insertsort(a,6);
cout<<"输出直接插入排序后升序排列的数组:";
for(int i=0;i<6;i++)
cout<<a[i]<<" ";
return 0;
}
4.选择排序(Selection Sort)
简单选择排序(Simple selection sort)
思想:通过n-i次关键字间的比较,每一趟在n-i-1(i=1,2,...,n-1)个记录中选取关键字最小的记录作为有序序列中的第i个记录(与第i个记录交换)。
时间复杂度:O(n^2)
空间复杂度:
//简单选择排序
#include <iostream>
using namespace std;
void selectsort(int *,int);
int main()
{
int a[6]={-2,1,0,5,4,3};
selectsort(a,6); //第二个参数表示第一个元素的下标 第三个参数表示最后一个元素的下标
for (int i=0;i<6;++i)
cout<<a[i]<<" ";
cout<<endl;
return 0;
}
void selectsort(int *a,int n)
{
int i,j;
for(i=1;i<n;i++)
{
int min=i;
for(j=i+1;j<n+1;j++)
if(a[j]<a[min])
min=j; //****找最小值的方法:内层循环结束后找到最小的值的下标
if(i!=min)
swap(a[i],a[min]);
}
}
此程序的难点:选出最小的元素的方法。
5.归并排序(Merging Sort)
是一类不同的排序方法,“归并”的含义:将两个或两个以上的有序表组合成一个新的有序表。
2-路归并排序
思想:假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2]个长度为2的有序子序列;再两两归并,……,重复,直至得到一个长度为n的有序序列为止。
时间复杂度:O(nlogn)
空间复杂度:
6.希尔排序(Shell Sort)
又称缩小增量排序,属于插入类排序。
思想:先将整个待排记录序列分割成为若干子序列分别进行直接插入排序,(相隔某个“增量”的记录组成一个子序列),待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。
时间复杂度:随增量变化。
空间复杂度:
7.堆排序(Heap Sort)