这段介绍参考百度百科,编译器函数库自带的快速排序函数qsort。使用qsort()排序并用 bsearch()搜索是一个比较常用的组合,使用方便快捷。
头文件:stdlib.h
用 法: void qsort(void *base, int nelem, int width, int (*fcmp)(const void *, const void *));
参数: 1 待排序数组首地址
2 数组中待排序元素数量
3 各元素的占用空间大小
4 指向函数的指针,用于确定排序的顺序
整数快排
int cmp1(const void *a, const void *b)
{
return *(int*)a - *(int*)b;
}
qsort(num, len, sizeof(int), cmp1);
#include
#include
//整数从小到大排序
int cmp1(const void *a, const void *b)
{
return *(int*)a - *(int*)b;
}
//整数从大到小排序
int cmp2(const void *a, const void *b)
{
return *(int*)b - *(int*)a;
}
int main()
{
int num[8] = {4,11,2,-3,15,4,0,7};
int len = 8;
int i;
printf("整数从小到大排序:\n");
qsort(num, len, sizeof(int), cmp1);
for(i = 0; i < len; i ++)
{
printf("%d ", num[i]);
}
printf("\n\n");
printf("整数从大到小排序:\n");
qsort(num, len, sizeof(int), cmp2);
for(i = 0; i < len; i ++)
{
printf("%d ", num[i]);
}
printf("\n");
system("PAUSE");
return 0;
}
运行结果如下图所示:
二维数组快排
int cmp(const void *a, const void *b)
{
return ((int*)a)[0] - ((int*)b)[0];
}
qsort(num, len, sizeof(int)*2, cmp);
#include
#include
//二维数组按照num[i][0]从小到大排序
int cmp(const void *a, const void *b)
{
return ((int*)a)[0] - ((int*)b)[0];
}
int main()
{
int num[6][2] = {
4, 1,
11, 2,
2, 3,
-3, 4,
15, 5,
0, 7,
};
int len = 6;
int i;
printf("排序前:\n");
for(i = 0; i < len; i ++)
{
printf("%4d %4d\n", num[i][0], num[i][1]);
}
printf("\n");
qsort(num, len, sizeof(int)*2, cmp);
printf("排序后:\n");
for(i = 0; i < len; i ++)
{
printf("%4d %4d\n", num[i][0], num[i][1]);
}
printf("\n");
system("PAUSE");
return 0;
}
运行结果如下图所示,其中num[i][0]和num[i][1]同时移动。
字符串快排
int cmp(const void *a, const void *b)
{
return *(char*)a - *(char*)b;
}
qsort(str, sum, sizeof(char)*10, cmp);
#include
#include
int cmp(const void *a, const void *b)
{
return *(char*)a - *(char*)b;
}
int main()
{
char str[7][10] = {
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Staturday",
"Sunday"
};
int sum = 7;
int i;
printf("排序前:\n");
for(i = 0; i < sum; i++)
{
printf("%s\n", str[i]);
}
printf("\n");
qsort(str, sum, sizeof(char)*10, cmp);
printf("排序后:\n");
for(i = 0; i < sum; i++)
{
printf("%s\n", str[i]);
}
printf("\n");
system("PAUSE");
return 0;
}
同int类型一样,输出如下所示: double快排
int cmp(const void *a, const void *b)
{
return *(double*)a > *(double*)b ? 1 : -1;
}
qsort(num, sum, sizeof(double), cmp);
#include
#include
int cmp(const void *a, const void *b)
{
return *(double*)a > *(double*)b ? 1 : -1;
}
int main()
{
double num[7] = {
12.2324,
-4.3457,
0.00000,
5.64375,
1.25879,
0.00001,
7.85435
};
int sum = 7;
int i;
printf("排序前:\n");
for(i = 0; i < sum; i++)
{
printf("%10f\n", num[i]);
}
printf("\n");
qsort(num, sum, sizeof(double), cmp);
printf("排序后:\n");
for(i = 0; i < sum; i++)
{
printf("%10f\n", num[i]);
}
printf("\n");
system("PAUSE");
return 0;
}
输出如下图所示: 结构体排序
int compare1(const void *a,const void *b)
{
return ((Student*)a)->score - ((Student*)b)->score;
}
qsort(s, N, sizeof(Student), compare1);
#include
#include
#define N 6
typedef struct
{
char name[15];
int score;
}Student;
int compare1(const void *a,const void *b)
{
return ((Student*)a)->score - ((Student*)b)->score;
}
int compare2(const void *a,const void *b)
{
return *(((Student*)a)->name) - *(((Student*)b)->name);
}
int main()
{
Student s[N] =
{
"Zhang San", 94,
"Li Si", 80,
"You", 94,
"I", 100,
"He", 72,
"She", 60
};
int i;
printf("按照分数排序:\n");
qsort(s, N, sizeof(Student), compare1);
for(i = 0; i < N; i++)
{
printf("%-15s : %d\n", s[i].name, s[i].score);
}
printf("\n");
qsort(s, N, sizeof(Student), compare2);
printf("按照姓名排序:\n");
for(i = 0; i < N; i++)
{
printf("%-15s : %d\n", s[i].name, s[i].score);
}
system("PAUSE");
return 0;
}
代码输出如下图所示: 由于MoreWindows写的白话文系列太好,所以这部分主要参考他的文章和《算法设计与分析》关于分治法那章内容。强烈推荐大家阅读系列文章,原文链接:
http://blog.csdn.net/morewindows/article/details/6684558
分治法的思想将一个大问题分割成小规模问题各个击破,分而治之,常用递归解决。常用的包括二分查找、归并排序和快速排序等应用。其中思想如下所示:
divide-and-conquer(P)
{
if(|P|<=n0) adhoc(p); //解决小规模问题
divide P into smaller subinstances P1,P2…Pk;
for(i=1; i<=k; i++) {
yi = divide-and-conquer(Pi); //分解
}
return merge(y1,y2…yk); //合并子算法
}
关于快速排序,由于它的时间复杂度在O(N*logN)效率较高,经常使用。该算法的基本思想:
1. 先从数列中取出一个数作为基准数。
2. 分区过程,将比这个数大的全放到它右边,小于或等于它的全放到它的左边。
3. 再对左右区间重复第二步,直到各区间只有一个数。
MoreWindows对快速排序作了进一步的说明:挖坑填数+分治法
以一个数组作为示例,取区间第一个数为基准数。
初始时,i = 0; j = 9; X = a[i] = 72
由于已经将a[0]中的数保存到X中,可以理解成在数组a[0]上挖了个坑,可以将其它数据填充到这来。
从j开始向前找一个比X小或等于X的数。当j=8,符合条件,将a[8]挖出再填到上一个坑a[0]中。a[0]=a[8]; i++; 这样一个坑a[0]就被搞定了,但又形成了一个新坑a[8],这怎么办了?
简单,再找数字来填a[8]这个坑。这次从i开始向后找一个大于X的数,当i=3,符合条件,将a[3]挖出再填到上一个坑中a[8]=a[3]; j--; 数组变为:
i = 3; j =7; X=72
再重复上面的步骤,先从后向前找,再从前向后找。
从j开始向前找,当j=5,符合条件,将a[5]挖出填到上一个坑中,a[3] = a[5]; i++;
从i开始向后找,当i=5时,由于i==j退出。此时,i = j = 5,而a[5]刚好又是上次挖的坑,因此将X填入a[5]。数组变为:
可以看出a[5]前面的数字都小于它,a[5]后面的数字都大于它。因此再对a[0…4]和a[6…9]这二个子区间重复上述步骤就可以了。
对挖坑填数进行总结:
1. i =L; j =R; 将基准数挖出形成第一个坑a[i]。
2. j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。
3. i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。
4. 再重复执行2,3二步,直到i==j,将基准数填入a[i]中。
照着这个总结很容易实现挖坑填数的代码:
分治法:
void quick_sort1(int s[], int l, int r)
{
if (l < r)
{
int i = AdjustArray(s, l, r);//先成挖坑填数法调整s[]
quick_sort1(s, l, i - 1); // 递归调用
quick_sort1(s, i + 1, r);
}
}
挖坑填数:
int AdjustArray(int s[], int l, int r) //返回调整后基准数的位置
{
int i = l, j = r;
int x = s[l]; //s[l]即s[i]就是第一个坑
while (i < j)
{
// 从右向左找小于x的数来填s[i]
while(i < j && s[j] >= x)
j--;
if(i < j)
{
s[i] = s[j]; //将s[j]填到s[i]中,s[j]就形成了一个新的坑
i++;
}
// 从左向右找大于或等于x的数来填s[j]
while(i < j && s[i] < x)
i++;
if(i < j)
{
s[j] = s[i]; //将s[i]填到s[j]中,s[i]就形成了一个新的坑
j--;
}
}
//退出时,i等于j。将x填到这个坑中。
s[i] = x;
return i;
}
PS:去一些大公司面试,经常会让你手写快排、二叉树非递归遍历、链表翻转等下面讲一个经典的题目。做过LeetCode的肯定做个这个题目,LeetCode的第一题Two Sum,求两个数的和。链接:https://leetcode.com/problems/two-sum/
Given an array of integers, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.
You may assume that each input would have exactly one solution.
Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2
//定义结构 因为需要数组值和下标同时排序
typedef struct NODE {
int value;
int pos;
}node;
//调用cmp排序实现结构排序
int cmp(const void *a, const void *b)
{
return ((node *)a)->value - ((node *)b)->value;
}
int* twoSum(int* nums, int numsSize, int target) {
int *result;
int i,j;
int sum;
node *numNode;
result=(int*)malloc(sizeof(int)*2);
numNode=(node*)malloc(sizeof(node)*numsSize);
for(i=0; i
当然你也可以调用unordered_map实现哈希表O(n)算法:
class Solution {
public:
vector twoSum(vector& nums, int target) {
vector vec;
unordered_map map;
for(int i=0; i