一、冒泡排序法(bubble sort)的基本思想是,通过相邻两个记录 之间的比较和交换,使关键码较小的记录逐渐从底部移向顶 部(上升),关键码较大的记录逐渐从顶部移向底部(沉 底),冒泡由此得名;冒泡排序属于交换类排序
排序算法是稳定的,数组存储或链表存储都可以冒泡排序,冒泡排序最好情况的时间复杂度O(N),最坏情况的时间复杂度是O(N2),对于N个数进行冒泡排序,最坏情况下需要进行的比较次数为N*(N-1)/2;
/*冒泡排序--双重循环*/ void BubbleSort(int arr[],int n) { int i, j; for(i=0; i<n-1; ++i) for(j=0; j<n-i-1; ++j) if(arr[j]<arr[j+1]){ int t = arr[j]; arr[j] = arr[j+1]; arr[j+1] = t; } }
/* 冒泡排序--优化双重循环 */ #include <stdio.h> void swap(int *a, int *b){ int t = *a; *a = *b; *b = t; } void bubbleSort(int *a, int n){ for(int i=n-1, swapped = 1; i>=1 && swapped; --i){ //比较n-1趟 并 控制下标 swapped = 0; for(int j=0; j<i; ++j){ //每趟相邻元素两两比较, 最大下标 n-1 if(a[j]>a[j+1]){ swap(&a[j],&a[j+1]); swapped = 1;//是否发生交换的标志 } } } } int main() { int arr[10] = {6,5,4,3,2,1}; //{1,2,3,4,5,6}; bubbleSort(arr,6); for(int i=0; i<6; ++i){ printf("%d\t", arr[i]); } return 0; }
/*冒泡排序--下标left至下标right*/ void BubbleSort(int arr[],int left, int right) { if(right > left){ int i, j; for(i=0; i<right-left; ++i) for(j=left; j<right-i; ++j) if(arr[j]<arr[j+1]){ int t = arr[j]; arr[j] = arr[j+1]; arr[j+1] = t; } } }
/*冒泡排序--递归*/ void BubbleSort(int *a,int left, int right) { if(left<right){ int j,t; for(j=right; left<j; j--){ if(a[j-1]>a[j])/*相邻比较*/ t=a[j],a[j]=a[j-1],a[j-1]=t; } BubbleSort(a,j+1,right);/*递归*/ } }
二、快速排序
选择一个基数,把待排序的数据分成左边比它小、右边比它大两个部分,再对左边、右边的数据以此类推,最终完成排序。快速排序属于交换类排序,算法不稳定
1、交换法
以数组左边的第一个数据为基数,设定左指针指向基数,设定右指针指向数组最右边的数据,在左右指针不出界的情况下,向右移动左指针找到比基数大的数停下,向左移动右指针找到比基数小的停下,在左指针小于右指针的情况下,交换两个数,循环左右指针的移动和数据交换,一旦左指针小于右指针的条件不成立(右指针指向数据一定不大于基数),基数与右指针指向的数据交换,基数有序位置确定,即基数左边小右边大;基数左右数据以此类推,递归完成排序。
1 /*快速排序*/ 2 #include <stdio.h> 3 void QuickSort(int *a,int n, int left, int right) 4 { 5 int i,j,t; 6 /*左指针left指向数组头 右指针right指向数组尾*/ 7 if(left<right){ 8 i=left,j=right+1;/*左右指针*/ 9 while(i<j){ 10 while(i+1<n && a[++i]<a[left]);/*左指针右移 指向大于基数的数据停止*/ 11 while(j-1>-1 && a[--j]>a[left]);/*右指针左移 指向小于基数的数据停止*/ 12 if(i<j)/*满足左指针小于右指针的条件 两指针指向数据交换*/ 13 t=a[i],a[i]=a[j],a[j]=t; 14 } 15 t=a[left],a[left]=a[j],a[j]=t;/*右指针指向数据与基数交换*/ 16 QuickSort(a,n,left,j-1);/*左边数据递归*/ 17 QuickSort(a,n,j+1,right);/*右边数据递归*/ 18 } 19 } 20 21 int main() 22 { 23 int i, arr[5]={20,40,0,15,60}; 24 QuickSort(arr,5,0,4); 25 for(i=0; i<5; ++i) 26 printf("%d ",arr[i]); 27 printf("\n"); 28 return 0; 29 }
2、补空位法
设定左右指针分别指向数组的头、尾,以最左边的数为基数,提取保存,左指针指向的基数位为空位,在右指针大于左指针的条件下,向左移动右指针,一旦发现比基数小的数据,该数据赋值到左指针指向的空位,右指针指向的为空位,在左指针小于右指针的条件下,向右移动左指针,一旦发现比基数大的数,该数据赋值到右指针指向的空位,左指针指向的位置为空位,一旦左指针不小于右指针,把基数赋值到右指针所指空位,基数有序定位,即基数左边小、右边大;基数左右数据以此类推,递归完成排序。
1 /*快速排序*/ 2 #include <stdio.h> 3 4 void QuickSort(int *a, int left, int right) 5 { 6 int i,j,t; 7 /*左指针left指向数组头 右指针right指向数组尾*/ 8 if(left<right){ 9 i=left,j=right,t=a[left];/*左右指针 提取基数*/ 10 while(i<j){ 11 while(i<j && a[j]>=t) j--;/*右指针左移 指向小于基数的数据停止*/ 12 a[i]=a[j]; /*补空位*/ 13 while(i<j && a[i]<=t) i++;/*左指针右移 指向大于基数的数据停止*/ 14 a[j]=a[i]; /*补空位*/ 15 } 16 a[j]=t;/*右指针指向数据即基数应在的位置 基数定位*/ 17 QuickSort(a,left,j-1);/*左边数据递归*/ 18 QuickSort(a,j+1,right);/*右边数据递归*/ 19 } 20 } 21 22 int main() 23 { 24 int i, arr[5]={20,40,0,15,60}; 25 QuickSort(arr,0,4); 26 for(i=0; i<5; ++i) 27 printf("%d ",arr[i]); 28 printf("\n"); 29 return 0; 30 }
三、优化快排(浙大 数据结构)
1、直接调用库函数
1 /* 快速排序 - 直接调用库函数 */ 2 3 #include <stdlib.h> 4 5 /*---------------简单整数排序--------------------*/ 6 int compare(const void *a, const void *b) 7 { /* 比较两整数。非降序排列 */ 8 return (*(int*)a - *(int*)b); 9 } 10 /* 调用接口 */ 11 qsort(A, N, sizeof(int), compare); 12 /*---------------简单整数排序--------------------*/ 13 14 15 /*--------------- 一般情况下,对结构体Node中的某键值key排序 ---------------*/ 16 struct Node { 17 int key1, key2; 18 } A[MAXN]; 19 20 int compare2keys(const void *a, const void *b) 21 { /* 比较两种键值:按key1非升序排列;如果key1相等,则按key2非降序排列 */ 22 int k; 23 if ( ((const struct Node*)a)->key1 < ((const struct Node*)b)->key1 ) 24 k = 1; 25 else if ( ((const struct Node*)a)->key1 > ((const struct Node*)b)->key1 ) 26 k = -1; 27 else { /* 如果key1相等 */ 28 if ( ((const struct Node*)a)->key2 < ((const struct Node*)b)->key2 ) 29 k = -1; 30 else 31 k = 1; 32 } 33 return k; 34 } 35 /* 调用接口 */ 36 qsort(A, N, sizeof(struct Node), compare2keys); 37 /*--------------- 一般情况下,对结构体Node中的某键值key排序 ---------------*/
2、快速排序(优化)
24行代码为什么是,High = Right-1; 调用Median3函数后,返回的Pivot位于Right-1,因Right的值是大于Right-1的值的,比较的时候,High是先--再比较的,所以比较的是Right-2的值;
Pivot的值一般定义为小于100的数;
1 /* 快速排序 */ 2 3 ElementType Median3( ElementType A[], int Left, int Right ) 4 { 5 int Center = (Left+Right) / 2; 6 if ( A[Left] > A[Center] ) 7 Swap( &A[Left], &A[Center] ); 8 if ( A[Left] > A[Right] ) 9 Swap( &A[Left], &A[Right] ); 10 if ( A[Center] > A[Right] ) 11 Swap( &A[Center], &A[Right] ); 12 /* 此时A[Left] <= A[Center] <= A[Right] */ 13 Swap( &A[Center], &A[Right-1] ); /* 将基准Pivot藏到右边*/ 14 /* 只需要考虑A[Left+1] … A[Right-2] */ 15 return A[Right-1]; /* 返回基准Pivot */ 16 } 17 18 void Qsort( ElementType A[], int Left, int Right ) 19 { /* 核心递归函数 */ 20 int Pivot, Cutoff, Low, High; 21 22 if ( Cutoff <= Right-Left ) { /* 如果序列元素充分多,进入快排 */ 23 Pivot = Median3( A, Left, Right ); /* 选基准 */ 24 Low = Left; High = Right-1; 25 while (1) { /*将序列中比基准小的移到基准左边,大的移到右边*/ 26 while ( A[++Low] < Pivot ) ; 27 while ( A[--High] > Pivot ) ; 28 if ( Low < High ) Swap( &A[Low], &A[High] ); 29 else break; 30 } 31 Swap( &A[Low], &A[Right-1] ); /* 将基准换到正确的位置 */ 32 Qsort( A, Left, Low-1 ); /* 递归解决左边 */ 33 Qsort( A, Low+1, Right ); /* 递归解决右边 */ 34 } 35 else InsertionSort( A+Left, Right-Left+1 ); /* 元素太少,用简单排序 */ 36 } 37 38 void QuickSort( ElementType A[], int N ) 39 { /* 统一接口 */ 40 Qsort( A, 0, N-1 ); 41 }
1 #include <stdio.h> 2 #define MAXN 50 3 4 typedef int ElementType; 5 void Swap(int*a, int*b) 6 { 7 int t = *a; 8 *a = *b; 9 *b = t; 10 } 11 12 ElementType Qselect( ElementType A[], int K, int Left, int Right ) 13 { 14 ElementType Pivot = A[Left]; 15 int L = Left, R = Right+1; 16 17 while (1) { 18 while (A[++L] < Pivot ) ; 19 20 while (A[--R] > Pivot ); 21 22 if (L < R ) Swap( &A[L], &A[R] ); 23 else break; 24 } 25 26 Swap( &A[Left], &A[R] ); 27 28 /* printf("\nLeft=%d,L=%d,Right=%d,R=%d,K=%d,L-Left=%d,Pivot=%d\n",Left,L,Right,R,K,L-Left,Pivot); */ 29 30 if ( K < (L-Left) ) 31 return Qselect(A, K, Left, R-1); 32 else if ( K > (L-Left) ) 33 return Qselect(A, K-(L-Left), L, Right); 34 else 35 return Pivot; 36 } 37 38 int quick_sort(int a[], int l, int r, int k) 39 { 40 int i,j; 41 i = l; j = r; 42 int x = a[l]; 43 int t = a[l]; a[l] = a[r]; a[r] = t; 44 while (i < j) 45 { 46 while (i < j && a[i]<x) i++; 47 if (i < j) 48 { 49 a[j] = a[i]; 50 j--; 51 } 52 while (i<j && a[j]>x) j--; 53 if (i < j) 54 { 55 a[i] = a[j]; 56 i++; 57 } 58 } 59 a[i] = x; 60 61 if (i - l + 1 == k) 62 return a[i]; 63 else if (i - l + 1 < k) 64 return quick_sort(a, i + 1, r, k - (i - l + 1)); 65 else return 66 quick_sort(a,l,i-1,k); 67 } 68 69 int main() 70 { 71 int a[10] = {-1,2,3,0,5,6,7,8,9,10};//{10,9,8,7,6,5,4,3,2,1};// {1,2,3,4,5,6,7,8,9,10};// 72 for(int i=1; i<=10; ++i) 73 printf("%d ",Qselect(a,i,0,9)); 74 /* printf("%d ",quick_sort(a,0,9,i)); */ 75 printf("\n"); 76 for(int i=0; i<=9; ++i) 77 printf("%d ",a[i]); 78 return 0; 79 }