前面介绍了三种排序算法:冒泡排序,插入排序以及选择排序,这篇文章介绍最常用的排序算法,快速排序
快速排序即从待排序序列中任意选择一个元素,作为基准,然后将多有小于基准的元素放在基准之前,大于基准的元素放在基准之后,等于基准的元素随意,这个过程为分组,再以递归的方式分别对基准之前和基准之后的分组继续进行分组,直到每个分组内的元素个数不多于一个为止 |
下面给出一个快速排序的接口:
void qsort(int data[], int left, int right)
{
int i;
int j;
int temp;
int swap = 0;
if(left > right)
{
return;
}
i = left;
j = right;
temp = data[left];
while( i != j)
{
while(data[j] >= temp && i < j)
{
j--;
}
while(data[i] <= temp && i < j)
{
i++;
}
if(i < j)
{
swap = data[i];
data[i] = data[j];
data[j] = swap;
}
}
data[left] = data[i];
data[i] = temp;
qsort(data, left, i - 1);
qsort(data, i + 1, right);
}
平均时间复杂度:O(NlogN)
非稳定排序,如果每次都能均匀分组,则排序最快,而选择中间位置作为基准,产生均匀分组的概率最高。
快速排序在Linux下有一个封装好的函数:qsort
qsort(void* base, size_t nmemb, size_t size, int(*compar)(const void*, const void*))
参数:
1、任意类型数组的首地址
2、数组元素个数
3、数组元素字节数
4、比较函数指针
compar参数指向一个函数:
ex:int xxx(const void* a, const void* b);
if(a > b) return 正数
if(a < b) return 负数
if(a == b) return 0
值得一提的是这个函数可对任意事物进行排序,在比较字符串的时候需要使用strcmp函数。
下面给个用例:
/*********************************************************************************
* Copyright: (C) 2017 tangyanjun<519656780@qq.com>
* All rights reserved.
*
* Filename: qsort.c
* Description: This file
*
* Version: 1.0.0(07/26/2017)
* Author: tangyanjun <519656780@qq.com>
* ChangeLog: 1, Release initial version on "07/26/2017 07:40:40 PM"
*
********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Student{
char name[20];
int age;
}STUDENT;
/* 自己写函数实现qsort */
void _myqsort(void* base, size_t left, size_t right, size_t size, int(*compar)(const void*, const void*))
{
size_t p = (left + right) / 2;
void* pivot = malloc(size);
memcpy(pivot, base + p * size, size);
size_t i = left;
size_t j = right;
while(i < j)
{
for(; !(i >= p || compar(pivot, base + i * size) < 0); ++i);
if(i < p)
{
memcpy(base + p * size, base + i * size, size); //内存拷贝
p = i;
}
for(; !(j <= p || compar(base + j * size, pivot) < 0); --j);
if(j > p)
{
memcpy(base + p * size, base + j * size, size);
p = j;
}
}
memcpy(base + p * size, pivot, size);
free(pivot);
if(p - left > 1)
{
_myqsort(base, left, p - 1, size, compar);
}
if(right - p > 1)
{
_myqsort(base, p + 1, right, size, compar);
}
}
void myqsort(void* base, size_t nmemb, size_t size, int(*compar)(const void*, const void*))
{
_myqsort(base, 0, nmemb - 1, size, compar);
}
int stu_cmp(const void* a, const void* b)
{
const STUDENT* pa = (const STUDENT*)a;
const STUDENT* pb = (const STUDENT*)b;
int res = strcmp(pa->name, pb->name); //先比较姓名大小
if(!res)
{
return pa->age - pb->age; //姓名大小一样,则按年龄升序
}
return -res;
}
int int_cmp(const void* a, const void* b)
{
return *(const int*)b - *(const int*)a;
}
int str_cmp(const void* a, const void* b) //字母的ASCII码值
{
return strcmp(*(const char* const*)a, *(const char* const*)b);
}
int main(int argc, char **argv)
{
int na[] = {55, 22, 33, 11, 44, 88, 99, 0, 77, 66};
size_t size = sizeof(na[0]);
size_t nmemb = sizeof(na) / size;
qsort(na, nmemb, size, int_cmp);
size_t i;
for(i = 0; i < nmemb; ++i)
{
printf("%d ", na[i]);
}
printf("\n");
const char* sa[] = {"beijing", "tianjin", "shanghai", "chongqing"};
size = sizeof(sa[0]);
nmemb = sizeof(sa) / size;
qsort(sa, nmemb, size, str_cmp);
for(i = 0; i < nmemb; ++i)
{
printf("%s ", sa[i]);
}
printf("\n");
STUDENT ta[] = {
{"zhangfei", 25},
{"zhaoyun", 22},
{"zhangfei", 20},
{"zhaoyun", 23},
{"guanyu", 50},
};
size = sizeof(ta[0]);
nmemb = sizeof(ta) / size;
qsort(ta, nmemb, size, stu_cmp);
for(i = 0; i < nmemb; ++i)
{
printf("%s/%d ", ta[i].name, ta[i].age);
}
printf("\n");
return 0;
}
结果:
[tangyanjun@VM_216_80_centos sort]$ gcc qsort.c
[tangyanjun@VM_216_80_centos sort]$ a.out
99 88 77 66 55 44 33 22 11 0
beijing chongqing shanghai tianjin
zhaoyun/22 zhaoyun/23 zhangfei/20 zhangfei/25 guanyu/50