作者:jofranks 原创作品,转载请标明出处!版权所有,侵权必究!
来源:http://blog.csdn.net/jofranks
交换排序的基本思想是:两两比较待排序的数据,发现两个数据的次序相反则进行交换,直到没有反序的数据为止。
本文交换排序有:冒泡排序,快速排序~!
一、冒泡排序
冒泡排序是一种稳定的排序算法,他的时间复杂度是O(n^2) 当然,当数据基本有序的时候,他可以达到线性复杂度!
OK,发一个冒泡排序的动画演示: 冒泡排序动画演示
他的算法基本思想是:
最多进行n-1趟排序,每趟排序时,从底部向上扫描,一旦发现两个相邻的元素不符合规则,则交换。我们 发现,第一趟排序后,最小值在A[1],第二趟排序后,较小值在A[2],第n-1趟排序完成后,所有 元素完全按 顺序排列。
下面来看一下排序的过程:
待排序数据:53 33 19 53 3 63 82 20 19 39
第一趟排序:3 53 33 19 53 19 63 82 20 39
第二趟排序:3 19 53 33 19 53 20 63 82 39
第三趟排序:3 19 19 53 33 20 53 39 63 82
第四趟排序:3 19 19 20 53 33 39 53 63 82
第五趟排序:没有反序数据,排序结束。
void bubble_sort(int *a, int N) { int temp; for(int i = N; i > 0; i--) { for(int j = 0; j < i - 1; j++) { if(a[j] > a[j + 1]) //大的放后面 { temp = a[j]; a[j] = a[j + 1]; a[j + 1] = temp; } } } }
ok 我们来看一下改进的冒泡排序,用一个标志:
void bubble_sort1(int *a, int N) { int temp; int n; for(int i = N - 1; i > 0;) { n = i; //记录交换的位置 i = 0; //假设本次没有交换 for(int j = 0; j < n; j++) { if(a[j] > a[j + 1]) { temp = a[j]; a[j] = a[j + 1]; a[j + 1] = temp; i = j + 1; } } } }
二、鸡尾酒排序
他是冒泡排序的一种改进,与冒泡排序不同的地方就是在排序时以双向在序列中进行排序!
他的时间复杂度是O(n^2) 但是,如果数据基本有序的情况下 复杂度将是线性的!
ok下面来看一下代码:
void Cocktal_sort(int *a, int N) { int temp; int M = N - 1; for(int i = 0; i < M;) { for(int j = M; j > i; j--) //将最小的数据排在前面 { if(a[j] < a[j - 1]) { temp = a[j]; a[j] = a[j - 1]; a[j - 1] = temp; } } i++; //将最大的数据排在后面 for(int j = i; j < M; j++) { if(a[j] > a[j + 1]) { temp = a[j]; a[j] = a[j + 1]; a[j + 1] = temp; } } M--; } }
三、快速排序
快速排序是一种不稳定的算法, 他的时间复杂度是O(nlgn) 空间复杂度是O(nlgn)
他是采用分治法!
在A[1..n]中任取一个数据元素作为比较的“基准”(不妨记为X),将数据区划分为左右两个部分:A[1..i-1]和A[i+1..n],且A[1..i-1]≤X≤A[i+1..n](1≤i≤n),当A[1..i-1]和A[i+1..n]非空时,分别对它们进行上述的划分过程,直至所有数据元素均已排序为止。
上面是一趟排序的过程!
ok,来看一个完整的例子!
待排序数据: 67 67 14 52 29 9 90 54 87 71
X=67 i j
扫描j i j
交换 54 67 14 52 29 9 90 67 87 71
扫描i i j
交换 54 67 14 52 29 9 67 90 87 71
j=i,结束 ij
第一趟排序后:54 67 14 52 29 9 [67] 90 87 71
第二趟排序后: 9 29 14 52 [54] 67 [67] 71 87 [90]
第三趟排序后:[9] 29 14 52 [54 67 67 71] 87 [90]
第四趟排序后:[9] 14 [29] 52 [54 67 67 71 87 90]
第五趟排序后:[9 14 29 52 54 67 67 71 87 90]
来看一下排序的过程:
① 选定基准X(不妨用A[low])
② j向前扫描,直到A[j]<X,交换A[i]与A[j],i+1。保证了A[low..i-1]≤X
③ i向后扫描,直到A[i]>X,交换A[i]与A[j],j-1。保证了X≤A[j..high]
④ 继续执行②、③,直到i=j。这时,X恰好在A[i]位置上。
⑤ 对序列A[low..i-1]及A[i+1..high]按照上述规律继续划分,直到序列为空。
仔细分析算法,我们发现,在排序中,我们总是用基准X与另一数据交换,因此,一趟排序结束后,X就能确切定位其最终位置。
OK,我们来看一下C递归代码:
//递归版本 void quick_sort(int *a, int left, int right) { int temp = a[left];//主元 if(left >= right) return ; int i = left, j = right; for(; i != j;) { //开始移动,分治计算,找出比主元大的和比主元小的!小的放前面,大的放后面 while(i < j && a[j] >= temp) j--; if(j >= i) a[i] = a[j]; while(i < j && a[i] <= temp) i++; if(j >= i) a[j] = a[i]; } a[i] = temp; //递归 quick_sort(a, left, i - 1); quick_sort(a, i + 1, right); }
OK,现在我们分开,看一下代码,先来看取第一个元素为主元:
//我们选首元素为主元 int pation(int *a, int left, int right) { int i = left; int j = right; int temp = a[left]; for(;i < j ;) { while(i < j && a[j] >= temp) j--; if(j >= i) a[i] = a[j]; while(i < j && a[i] <= temp) i++; if(j >= i) a[j] = a[i]; } a[i] = temp; return i; } void quick_sort1(int *a, int left, int right) { if(left < right) { int index = pation(a, left, right); quick_sort1(a, left, index - 1); quick_sort1(a, index + 1, right); } }
下面我们再换一种pation函数的写法,下面演示的主要是pation的不同了,所以我只贴这个函数的代码了!//以首元素为主元 int pation2(int *a, int left, int right) { int temp = a[left]; int n; int i = left; for(int j = i; j <= right; j++) { if(a[j] < temp) { i++; n = a[j]; a[j] = a[i]; a[i] = n; } } n = a[i]; a[i] = a[left]; a[left] = n; return i; }
下面再来一个将最后一个元素作为主元的情况://以最后一个元素为主元 int pation3(int *a, int left, int right) { int temp = a[right]; int n ; int i = left - 1; for(int j = left; j < right; j++) { if(a[j] <= temp) { //将小元素和大元素呼唤 i++; n = a[i]; a[i] = a[j]; a[j] = n; } } //将尾元素挪到第一个较大的元素的位置, //也就是说将尾元素和第一个较大的元素交换 n = a[i + 1]; a[i + 1] = a[right]; a[right] = n; return i + 1; }
ok先到这里,过几天把非递归实现补充上来!
---------2012/8/2
---------jofranks 于南昌