写在前面
本文主要介绍使用c语言实现快速排序与合并排序的两种方法,可供大家参考与学习,其中的代码参考自《计算机算法设计与分析》(第5版)中p22-p25中内容
快速排序
算法思想
代码
#include<stdio.h>
typedef int type;//自定义类型
void swap(type *a, type *b){
type c = *a;
*a = *b;
*b = c;
}
int partition(type a[], int p, int r){
int i = p, j = r + 1;//赋初始值
type x = a[p], c;
while(true){
while (a[++i] < x && i < r);//找到比初始值大的值,其下标为i
while (a[--j] > x);//找到比初始值小的值,其下标为j
if ( i >= j)
break;
swap(&a[i], &a[j]);//交换他们
// c = a[i];
// a[i] = a[j];
// a[j] = c;
}
//把初始值换到中间,满足算法的思想
a[p] = a[j];
a[j] = x;
return j;
}
void sort(type a[], int p, int r){
if ( p < r) {
int q = partition(a, p, r);//找到那个q
sort(a, p, q - 1);//排左边
sort(a, q + 1, r);//排右边
}
}
int main(){
int n = 11, i = 0;
type a[12] = { 8, 9, 6, 3, 7, 5, 4, 1, 10, 3, 2, 0 };
sort(a, 0, n);
for (i = 0; i <= n; i++){
printf("%d", a[i]);
}
}
时间复杂度
T
(
n
)
=
{
O
(
1
)
n
≤
1
T
(
n
−
1
)
+
O
(
n
)
n
>
1
T(n)=\begin{cases}O(1)&n\leq1\\T(n-1)+O(n)&n>1\end{cases}
T(n)={O(1)T(n−1)+O(n)n≤1n>1
∴
O
(
n
2
)
\therefore O(n^2)
∴O(n2)
合并排序
算法思想
代码
递归
#include <malloc.h>
#include <stdlib.h>
void merge(int A[], int L[], int R[], int l, int r) {
//两个有序序列L, R合并为A, l, r分别为L,R的长度
int i = 0, j = 0, k = 0;
while(i < l && j < r) { //两个子序列首元素做比较,小者取出置入父序列
if(L[i] <= R[j])
A[k++] = L[i++];
else
A[k++] = R[j++];
}
while(i < l) //将左半部分剩余元素置入父序列
A[k++] = L[i++];
while(j < r) //将右半部分剩余元素置入父序列
A[k++] = R[j++];
}
void mergesort(int A[], int n) //合并排序的递归主体
{
int i = 0, j = 0;
if(n > 1) //多于一个元素才需要排序
{
int mid = n / 2;
int *left = (int*)malloc(sizeof(int)*mid);
int *right = (int*)malloc(sizeof(int)*(n-mid));
for(i = 0; i < mid; i++)
left[i] = A[i]; //建立临时数组存储左半部分序列
for(j = mid; j < n; j++)
right[j - mid] = A[j]; //建立临时数组存储右半部分序列
mergesort(left, mid); //调用自身对左半部分进行合并排序
mergesort(right, n-mid); //调用自身对右半部分进行合并排序
merge(A, left, right, mid, n-mid); //两个有序序列的合并操作,封装为函数
free(left);
free(right);
}
}
int main(void) {
int a[] = {7, 4, 9, 1, 8};
mergesort(a, 5);
int index = 0;
printf("a : ");
for (index = 0; index < 5; index++) {
printf("%d", a[index]);
}
return 0;
}
非递归
#include<stdio.h>
#include<stdlib.h>
void mergesort(int A[], int n){ //非递归实现。只开辟一个大小与待排序数组相同的存储数组,排序过程中直接在该数组上进行操作。不反复开辟临时数组
int step;
int *p, *q, *t;
int i, j, k, len1, len2;
int *temp;
step = 1; //初始步长为1,即将单个元素作为有序子序列进行合并
p = A;
q = (int*)malloc(sizeof(int)*n); //q为临时开辟的空间,用来存储已排序序列,大小为待排序数组的长度
temp = q; //temp与q指向同一段内存,留作最后释放内存空间时使用,因为q指针在后面排序操作中可能会改变指向
while (step < n) {
i = 0;
j = i + step;
k = i; //k用作临时数组的下标
len1 = i + step < n ? i + step : n; //len1表示有序序列1的下标上限
len2 = j + step < n ? j + step : n; //len2表示有序序列2的下标上限
while (i<n) {
while (i<len1&&j<len2) //两个子序列首元素做比较,小者取出置入父序列
q[k++] = p[i]<p[j] ? p[i++] : p[j++];
while (i<len1) //将子序列1的剩余元素置入父序列
q[k++] = p[i++];
while (j<len2) //将子序列2的剩余元素置入父序列
q[k++] = p[j++];
i = j; //j经过自增变为len2,然后赋值给i
j = i + step; //i被赋值为len2,加上步长再赋值给j
k = i;
len1 = i + step < n ? i + step : n;
len2 = j + step < n ? j + step : n;
}
step *= 2; //步长翻倍,即将原步长2倍个数的数组元素作为有序子序列进行合并
t = p; //t作为临时指针变量,用于交换p和q的指针指向
p = q; //将p指针指向经过一轮合并排序后的临时数组
q = t; //将q指针指向原数组
}
if (A != p){ //如果最终p指针的指向改变为临时数组,则将完成排序的数组拷贝至原数组
memcpy(A, p, sizeof(int)*n);
}
free(temp);
}
int main(void) {
int a[] = {7, 4, 9, 1, 8};
mergesort(a, 5);
int index = 0;
printf("a : ");
for (index = 0; index < 5; index++) {
printf("%d", a[index]);
}
return 0;
}
时间复杂度
O ( n log n ) O(n\log{n}) O(nlogn)