冒泡排序
稳定
最差时间:O(n2)(反向有序)
平均时间:O(n2)
最好时间:O(n)(正向有序,作n-1次比较即可)
空间:O(1)
冒泡排序的线性实现,包括传统冒泡排序(MyBubble)以及参考书的冒泡排序方法(BookBubble),已经改进的冒泡排序():
#include <stdio.h>
#define MaxSize 100
#define Swap(x,y,t)((t)=(x),(x)=(y),(y)=(t))
typedef int T;
typedef struct list {
int Size,MaxList;
T Elements[MaxSize];
}List;
List CreateList(int n , int maxSize) {
List list;
int i ;
list.Size=n;
list.MaxList = maxSize;
for(i=0;i<n;i++) {
scanf("%d",&(list.Elements[i]));
}
return list;
}
void MyBubble(List *list) {
int i , j,temp;
for(i=1;i<=list->Size-1;i++) {
for(j=0;j<list->Size-i;j++) {
if(list->Elements[j]>list->Elements[j+1])Swap(list->Elements[j],list->Elements[j+1],temp);
}
}
}
void BookBubble(List *list) {
int j,i=list->Size-1;
T temp;
int sorted=0;
while(i>0&&!sorted) {
sorted=1;
for(j=0;j<i;j++) {
if(list->Elements[j+1]<list->Elements[j]) {
Swap(list->Elements[j],list->Elements[j+1],temp);
sorted=0;
}
}
i--;
}
}
/*
记录该趟排序最后一次被交换的两记录的位置,例如在某趟排序中最后发生交换的记录为Ks,Ks+1,
下趟排序的序列范围应为K0~Ki-1,改进后的排序将下趟排序范围定位K0~Ks
*/
void ModifyBubble(List *list) {
int i , j ,last;
T temp;
i = list->Size-1;
while(i>0) {
last=0;
for(j=0;j<i;j++) {
if(list->Elements[j+1]<list->Elements[j]) {
Swap(list->Elements[j],list->Elements[j+1],temp);
last=j;
}
}
i=last;
}
}
void PrintList(List list) {
int i;
for(i=0;i<list.Size-1;i++) {
printf("%d ",list.Elements[i]);
}
printf("%d\n",list.Elements[list.Size-1]);
}
void main() {
int n ,maxList;
List list;
while(scanf("%d%d",&n,&maxList)) {
list = CreateList(n,maxList);
// MyBubble(&list);
// BookBubble(&list);
ModifyBubble(&list);
PrintList(list);
}
}
快速排序
不稳定
最好时间:O(nlogn)[经过每一趟排序后,若被分割成两个大小相近的子序列时,效率最好]
平均时间:O(nlogn)
最差时间:O(n2) [反之,若每次分割的两个子序列中有一个为空,即初始序列有序(顺序或逆序),效率最低]
空间:O(logn)
基本思想:首先在待排序的序列(K0, K1, …, Kn-1)中选择一个记录作为分划元素,被称为主元(pivot)。
例如可以取序列的第一个记录为主元。
接着,以主元为轴心,经过一趟特殊的排序处理,实现对原序列的重新排列。
设在新序列中,主元处于位置k处。则新序列应满足条件:从位置0到位置k-1的所有记录的关键字值都小于或等于主元的值;
从位置k+1到位置n-1的所有记录的关键字值都大于或等于主元的值。这样,序列被分成三部分:主元和左、右两个子序列。
(1)将A[(left+right)/2]作为分割元素,与A[left]交换;
(2)选left到right间的随机整数k,将A[k]与A[left]交换;
(3)取A[left]、A[(left+right)/2]和A[right]之中间值与A[left]交换。
改进二、
(1)为提高快速排序的效率,将递归程序改为非递归的,具体做法:使用一个堆栈,在一次分划操作后,将其中一个序列的上下界进栈保存,而对另一个子序列继续进行分划排序。当处理这个子序列时,仍将分划得到的一个子序列的上下界进栈保存,对另一个子序列进行排序,直到分划所得的子序列中至多只有一个元素为止,再从栈中取出保存的某个尚未排序的子序列的上、下界对其进行快速排序。
(2)为减小栈空间,先对较小的子序列排序,将较大的子序列进栈,这样可使所需的栈空间的大小降为O(logn);附上快排完整实现代码:
#include <stdio.h> #define MaxSize 100 #define Swap(x,y,t)((t)=(x),(x)=(y),(y)=(t)) #define MaxNum 10000000 typedef int T; typedef struct list { int Size,MaxList; T Elements[MaxSize]; }List; List CreateList(int n , int maxSize) { List list; int i ; list.Size=n+1; list.MaxList = maxSize; for(i=0;i<n;i++) { scanf("%d",&(list.Elements[i])); } return list; } int Partition(List *list,int left,int right) { int i = left,j=right+1;//确定分划序列的指针i,j T temp; T pivot = list->Elements[left]; do { do i++ ; while(list->Elements[i]<pivot);//i从左向右找第一个不小于分割元素pivot的元素 do j-- ; while(list->Elements[j]>pivot);//j从又向左找第一个不大于分割元素pivot的元素 if(i<j)Swap(list->Elements[i],list->Elements[j],temp); //若i<j,则交换两个元素 }while(i<j); //交换分割元素Elements[left]和Elements[j] Swap(list->Elements[left],list->Elements[j],temp); return j ; } void QSort(List *list,int left,int right) { int k ; if(left<right) { k=Partition(list,left,right);//对left和right之间的序列进行分割 QSort(list,left,k-1);//对左子序列进行快速排序 QSort(list,k+1,right);//对右序列进行快速排序 } } void QuickSort(List *list) { list->Elements[list->Size]=MaxNum; QSort(list,0,list->Size-1); } void PrintList(List list) { int i; for(i=0;i<list.Size-1;i++) { printf("%d ",list.Elements[i]); } printf("%d\n",list.Elements[list.Size-1]); } void main() { int n ,maxList; List list; while(scanf("%d%d",&n,&maxList)) { list = CreateList(n,maxList); QuickSort(&list); PrintList(list); } }