c语言的两种排序方式(合并与快速)

写在前面

本文主要介绍使用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(n1)+O(n)n1n>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)

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值