《八大排序 详解(上)》
《八大排序 详解(中)》
紧接前两篇博文,我们这篇博文所要讲解的是我们前两篇博文编写的所有函数的使用、生成随机数组的函数的讲解以及一种及其凶悍的调用方法——指向函数的指针的使用,那么,废话不多说,开始我们的主题吧!
首先,本人要讲解的不是各种算法思想,而是能够生成随机数组的一些操作,这样对于我们接下来的各种算法的运行结果以及运行时间就能够进行检测,并且还排除偶然现象导致我们得出错误的结果。
那么,本人先来讲解一下关于产生随机数的操作,首先我要提到的是C语言中的rand()函数和srand()函数:
首先,这两个函数都存在于<stdlib.h>头文件中
其次,
int rand(void) :
返回一个范围在 0 到 RAND_MAX 之间的伪随机数。
(RAND_MAX 是一个常量,它的默认值在不同的实现中会有所不同,但是值至少32767)
void srand(unsigned int seed):
播种由函数 rand 使用的随机数发生器(seed – 这是一个整型值,用于伪随机数生成算法播种)
简单来说,这里的rand()函数,其实是已经从写好的随机数表中读取数字,而我们的srand()函数,可以理解为根据参数的不同,选取不同的随机数表来让rand()函数读。
而如果我们没写srand()函数而直接使用rand()函数的话,rand()函数就会默认之前写的是srand(1)
那么,有了上面的大概解释,能够了解到我们必须要保证srand()函数中的参数一直处于变化的状态,若我们使用变量来做参数,那么每次要产生随机数的时候又要改变变量的值,这间接等价于用随机数作为参数来产生随机数,这么一想,这个方法十分不合理,那么,我们该怎么实现呢?
这里就要再来介绍一个函数——time()函数。
time()函数:
存在于<time.h>头文件中;
当我们的参数为0时,这个函数的返回值会随着时间而改变,而这个函数的参数为0时的返回值为从C语言刚诞生那天的0时0分0秒到现在为止的秒数。
所以,这么看来,将这个函数的返回值作为rand()函数的参数就能够满足上面的要求了,就能够随时间的不同而产生不同的随机数了。
那么,现在我们来编写一个函数来产生随机数——随机数产生函数:
int *createRandData(int minValue, int maxValue, int count) { //参数是最小值、最大值和产生个数
int *res = NULL;
int index;
int randNum;
res = (int *) calloc(sizeof(int), count);
srand(time(0));
for (index = 0; index < count; index++) {
randNum = rand();
res[index] = randNum % (maxValue - minValue + 1) + minValue;
}
return res;
}
这里我们要提醒的一点是:一定要记得写上<malloc.h>、<stdlib.h>和<time.h>两个头文件,还有就是我们上面的代码中运用了calloc()函数,所以我们等代码快编写完后,一定要记得加上free()函数来释放动态申请的空间,以防出现“内存泄漏”
那么,随机数产生函数我们写好了,现在我们来编写一个显示数组函数,以便检查我们之后的排序是否有错
显示函数代码如下:
void showArray(int *array, int count) {
int i;
for (i = 0; i < count; i++) {
printf(i == 0 ? "%d" : ", %d", array[i]);
}
}
现在我们来编写一个主函数来尝试一下代码是否能够产生随机数并且显示出来:
int main() {
int *ar = NULL;
int minValue;
int maxValue;
int count;
printf("最小值 最大值 数据个数:");
scanf("%d%d%d", &minValue, &maxValue, &count);
ar = createRandData(minValue, maxValue, count);
showArray(ar, count);
free(ar);
return 0;
}
下面是我用VC6.0编译运行的结果,可以看到我们上面的函数都是编写正确的:
还有一点是,我们之后会用到boolean类型。所以来编写"mec.h"头文件:
#ifndef _MEC_H_
#define _MEC_H_
typedef unsigned char boolean;
#define TRUE 1
#define FALSE 0
#endif
那么,现在的基本工作已经做完了,现在我们来运用我们之前俩篇博文都在极力鼓吹的调用前几篇博文中的排序函数的方法吧:
一般人的调用方法是switch()函数或者if-else if语句,但是作为我们数据结构与算法专栏的最后几篇博文,当然不能和C的入门者一样去编程啦,而且,在本人的以往的博文《指向函数的指针——消费未来》这一篇博文中就讲过的一种方法——指向函数的指针
(相关知识请参考《指向函数的指针——消费未来》)
那么,话不多说,我们现在开始编程吧:
#define INSERT_SORT 0
#define INSS 0
#define CHOOSE_SORT 1
#define CHOICE_SORT 1
#define CHOIS 1
#define EXCHANGE_SORT 2
#define EXSORT 2
#define SHELL_SORT 3
#define SHELLS 3
#define HEAP_SORT 4
#define HEAPS 4
#define QUICK_SORT 5
#define QUICKS 5
#define MERGE_SORT 6
#define MERGE 6
#define BUCKET_SORT 7
#define BUCKET 7
typedef void (*SORT_FUNC)(int *, int);
const SORT_FUNC sortFunctionArray[] = {
insertSort,
chooseSort,
exchangeSort,
ShellSort,
heapSort,
quickSort,
mergeSort,
buckeySort,
};
void sort(int *array, int count, int sortType) {
if (sortType < 0 || sortType > sizeof(sortFunctionArray) / sizeof(SORT_FUNC)) {
return;
}
sortFunctionArray[sortType](array, count);
}
上面的代码看似短短几行,但是相比于以往我们的处理手法,类似于switch()和if-else if相比还是蛮具技术性的,相信好多同学在看到这段代码之后,也觉得眼前一亮,当初刚学到指向函数的指针时可能还没想到在这里还能够这样用。
那么,现在我来总结一下这三篇博文的全部内容吧:
mec.h:
#ifndef _MEC_H_
#define _MEC_H_
typedef unsigned char boolean;
#define TRUE 1
#define FALSE 0
#endif
util.h:
#ifndef _MEC_UTIL_H_
#define _MEC_UTIL_H_
#include "mec.h"
int *createRandData(int minValue, int maxValue, int count);
void showArray(int *array, int count);
#endif
util.c:
#include <stdio.h>
#include <malloc.h>
#include <time.h>
#include <stdlib.h>
#include "util.h"
int *createRandData(int minValue, int maxValue, int count) {
int *res = NULL;
int index;
int randNum;
res = (int *) calloc(sizeof(int), count);
srand(time(0));
for (index = 0; index < count; index++) {
randNum = rand();
res[index] = randNum % (maxValue - minValue + 1) + minValue;
}
return res;
}
void showArray(int *array, int count) {
int i;
for (i = 0; i < count; i++) {
printf(i == 0 ? "%d" : ", %d", array[i]);
}
}
sort.h:
#ifndef _MEC_SORT_H_
#define _MEC_SORT_H_
#include "util.h"
#define INSERT_SORT 0
#define INSS 0
#define CHOOSE_SORT 1
#define CHOICE_SORT 1
#define CHOIS 1
#define EXCHANGE_SORT 2
#define EXSORT 2
#define SHELL_SORT 3
#define SHELLS 3
#define HEAP_SORT 4
#define HEAPS 4
#define QUICK_SORT 5
#define QUICKS 5
#define MERGE_SORT 6
#define MERGE 6
#define BUCKET_SORT 7
#define BUCKET 7
void insertSort(int *array, int count);
void chooseSort(int *array, int count);
void exchangeSort(int *array, int count);
void ShellSort(int *array, int count);
void heapSort(int *array, int count);
void quickSort(int *array, int count);
void mergeSort(int* array, int count);
void bucketSort(int *array, int count);
void sort(int *array, int count, int sortType);
#endif
sort.c:
#include <stdio.h>
#include "mec.h"
#include "sort.h"
typedef void (*SORT_FUNC)(int *, int);
const SORT_FUNC sortFunctionArray[] = {
insertSort,
chooseSort,
exchangeSort,
ShellSort,
heapSort,
quickSort,
};
void sort(int *array, int count, int sortType) {
if (sortType < 0 || sortType > sizeof(sortFunctionArray) / sizeof(SORT_FUNC)) {
return;
}
sortFunctionArray[sortType](array, count);
}
static void insertSortOnce(int *array, int count, int start, int step);
static void adjustHeap(int *array, int count, int root);
static int qSortOnce(int *array, int start, int end);
static void qSort(int *array, int start, int end);
static void merge(int* array, int left, int right, int mid, int* temp);
static void mSort(int* array, int left, int right, int* temp);
static int findMaxNum(const int *array, int count);
static int findMinNum(const int *array, int count);
static int findMaxNum(const int *array, int count) {
int max = array[0];
int i;
for (i = 1; i < count; i++) {
if (array[i] > max) {
max = array[i];
}
}
return max;
}
static int findMinNum(const int *array, int count) {
int min = array[0];
int i;
for (i = 1; i < count; i++) {
if (array[i] < min) {
min = array[i];
}
}
return min;
}
static void mSort(int* array, int left, int right, int* temp) {
int mid;
if (left >= right) {
return;
}
mid = (left + right) / 2;
mSort(array, left, mid, temp);
mSort(array, mid + 1, right, temp);
merge(array, left, right, mid, temp);
}
static void merge(int* array, int left, int right, int mid, int* temp) {
int i = left;
int j = mid + 1;
int tempLeft = left;
int t = 0;
while (i <= mid && j <= right) {
temp[t] = array[i] <= array[j] ? array[i++] : array[j++];
t++;
}
while (i <= mid) {
temp[t++] = array[i++];
}
while (j <= right) {
temp[t++] = array[j++];
}
t = 0;
while (tempLeft <= right) {
array[tempLeft++] = temp[t++];
}
}
static void qSort(int *array, int start, int end) {
int middle;
if (start >= end) {
return;
}
middle = qSortOnce(array, start, end);
qSort(array, start, middle-1);
qSort(array, middle+1, end);
}
static int qSortOnce(int *array, int start, int end) {
int i = start;
int j = end;
int tmp = array[i];
while (i < j) {
while (i < j && array[j] > tmp) {
j--;
}
if (i < j) {
array[i++] = array[j];
}
while (i < j && array[i] < tmp) {
i++;
}
if (i < j) {
array[j--] = array[i];
}
}
array[i] = tmp;
return i;
}
static void adjustHeap(int *array, int count, int root) {
int leftChildIndex;
int rightChildIndex;
int maxValueIndex;
int tmp;
while (1) {
leftChildIndex = 2*root + 1;
if (leftChildIndex >= count) {
return;
}
rightChildIndex = 2*root + 2;
maxValueIndex = rightChildIndex >= count ? leftChildIndex
: (array[leftChildIndex] > array[rightChildIndex]
? leftChildIndex : rightChildIndex);
maxValueIndex = array[root] > array[maxValueIndex] ? root : maxValueIndex;
if (root == maxValueIndex) {
return;
}
tmp = array[root];
array[root] = array[maxValueIndex];
array[maxValueIndex] = tmp;
root = maxValueIndex;
}
}
static void insertSortOnce(int *array, int count, int start, int step) {
int i;
int j;
int t;
int tmp;
for (i = start + step; i < count; i += step) {
tmp = array[i];
for (j = start; j < i && tmp > array[j]; j += step)
;
for (t = i; t > j; t -= step) {
array[t] = array[t-step];
}
array[j] = tmp;
}
}
void bucketSort(int *array, int count){
int i = 0;
int j = 0;
int max = findMaxNum(array, count);
int min = findMinNum(array, count);
int length = max - min;
int *res = (int *)calloc(sizeof(int), length+1);
for (i = 0; i < count; i++) {
res[array[i] - min]++;
}
for(i = 0; i <= length; ++i) {
while(res[i]--) {
array[j++] = i + min;
}
}
free(res);
}
void mergeSort(int* array, int count) {
int *temp;
temp = (int *)calloc(sizeof(int), count);
mSort(array, 0, count-1, temp);
}
void quickSort(int *array, int count) {
printf("\nquick sort\n");
qSort(array, 0, count-1);
}
void heapSort(int *array, int count) {
int root;
int i;
int tmp;
printf("\nheap sort\n");
for (root = count/2 - 1; root > 0; root--) {
adjustHeap(array, count, root);
}
for (i = 0; i < count - 1; i++) {
adjustHeap(array, count - i, 0);
tmp = array[0];
array[0] = array[count - 1 - i];
array[count - 1 - i] = tmp;
}
}
void ShellSort(int *array, int count) {
int step;
int start;
printf("\nShell sort\n");
for (step = count/2; step; step /= 2) {
for (start = 0; start < step; start++) {
insertSortOnce(array, count, start, step);
}
}
}
void insertSort(int *array, int count) {
int i;
int j;
int t;
int tmp;
printf("\ninsert sort\n");
for (i = 1; i < count; i++) {
tmp = array[i];
for (j = 0; j < i && tmp > array[j]; j++)
;
for (t = i; t > j; t--) {
array[t] = array[t-1];
}
array[j] = tmp;
}
}
void chooseSort(int *array, int count) {
int i;
int j;
int minIndex;
int tmp;
printf("\nchoose sort\n");
for (i = 0; i < count-1; i++) {
for (minIndex = i, j = i+1; j < count; j++) {
if (array[minIndex] > array[j]) {
minIndex = j;
}
}
if (minIndex != i) {
tmp = array[i];
array[i] = array[minIndex];
array[minIndex] = tmp;
}
}
}
void exchangeSort(int *array, int count) {
int i;
int j;
int tmp;
boolean hasExchange;
printf("\nexchange sort\n");
for (i = count-1; i > 0; i--) {
for (hasExchange = FALSE, j = 0; j < i; j++) {
if (array[j] > array[j+1]) {
tmp = array[j];
array[j] = array[j+1];
array[j+1] = tmp;
hasExchange = TRUE;
}
}
if (!hasExchange) {
return;
}
}
}
和前几篇博文一样,这里的代码牵扯多文件,所以我们在运行时需要运用到命令行或者虚拟机进行运行。
学了这么久的数据结构与算法,我们能够发现,学习是一个不断积累,不断改进的过程,希望同学们再今后的学习中,能够有所体悟,并通过自己的经验以及一些想法能够创造出比先人更加优化的处理技巧。
程路漫漫,唯键作伴,加油!!!
那么,我们的排序到现在为止也就讲解完成了,希望大家能够在本人这三篇博文中有所收获,谢谢!!!