内部排序是指待排序列完全存放在内存中所进行的排序过程,适合不太大的元素序列。排序是计算机程序设计中的一种重要操作,其功能是对一个数据元素集合或序列重新排列成一个按数据元素某个相知有序的序列。排序分为两类:内排序和外排序。其中快速排序的是目前排序方法中被认为是最好的方法。内部排序方法:1.插入排序(直接插入排序);2.快速排序;3.选择排序(简单选择排序);4.归并排序;5.冒泡排序;6.希尔排序(希尔排序是对直接插入排序方法的改进);7.堆排序;——摘自百度百科
#ifndef SORT_H_ #define SORT_H_ #define ARRAY_LEN 1000 // 数组长度 #define MIN 1 // 数组的最小值 #define MAX 1000 // 数组的最大值 int Comparisons_num; // 比较次数 int Mobile_num; // 移动次数 void Create_data(int *a, int n, int min, int max); // 建立伪随机 void Copy_array(int *tar, int *arr, int len); // 复制数组 void Swap_element(int *a, int *b); // 交换元素 void Insert_sort(int *arr, int len); // #1 直接插入排序 void Shell_sort(int *arr, int len); // #2 希尔排序 void Bubble_sort(int *arr, int len); // #3 冒泡排序 int Division(int *a, int left, int right); // 分隔过程(快速排序) void Quick_sort(int *arr, int left, int right, int count); // #4 快速排序(left和count初始值为0,right初始值为数组长度 - 1) void Select_sort(int *arr, int len); // #5 选择排序 void Heap_adjust(int arr[], int i, int len); // 构成堆过程 (堆排序) void Heap_sort(int arr[], int len); // #6 堆排序 void Merge(int arr[], int target[], int start, int mid, int end); // 归并过程(归并排序) void Merge_sort(int arr[], int target[], int start, int end, int count); // #7 归并排序(start和count初始值为0,end初始值为数组长度 - 1) void Print_sort_positive(int *arr, int len); // 正序输出 void Print_sort_negative(int *arr, int len); // 逆序输出 void Print_mob_com(); // 显示移动次数和比较次数 #endif
在实现排序前,先定义函数的功能模块,即sort.h。
头文件中定义了三个常量为ARRAY_LEN,MIN和MAX,代表数组的长度为1000,最大值为1000,最小值为1;建立伪随机函数Create_data()、复制数组函数Copy_array()和交换元素函数Swap_element(),这三个函数功能为初始化数组的元素;七种内部排序的函数与过程的定义,最后定义了数组的正序和逆序输出,以及打印排序过程中元素的移动次数和比较次数。
#include#include #include #include #include #include <string.h> //#pragma warning (disable:4996) extern int Comparisons_num; // 比较次数 extern int Mobile_num; // 移动次数 // 建立伪随机数组 void Create_data(int *a, int n, int min, int max) { int flag; // 避免取重复取值 srand(time(NULL)); if (n > max - min + 1) return 0; for (int i = 0, j = 0; i ) { do { a[i] = (max - min + 1) * rand() / (RAND_MAX + 1) + 1; flag = 0; for (j = 0; j < i; j++) { if (a[i] == a[j]) flag = 1; } } while (flag); } } // 复制数组 void Copy_array(int *tar, int *arr, int len) { int i; for (i = 0; i < len; i++) tar[i] = arr[i]; } // 交换元素 void Swap_element(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; Mobile_num += 3; // 一次关键字交换计为3次移动 }
以上为文件sort.c中实现数组的初始化程序,函数Create_data()创建没有重复取值的数组,函数Copy_array()将数组arr全部内容复制到数组tar中,函数Swap_element()负责交换元素内容,每次调用移动次数Mobile_num将会增加三次。
// 直接插入排序 void Insert_sort(int *arr, int len) { int i, j; int tmp; // 待排序的元素 for (i = 0; i < len; i++) { tmp = arr[i]; for (j = i - 1; j >= 0 && tmp < arr[j]; j--) { Swap_element(arr + j, arr + j + 1); // tmp < arr[j],因此arr[j]向后移动 Comparisons_num++; } arr[j + 1] = tmp; } }
// 希尔排序 void Shell_sort(int *arr, int len) { int i, j; int d = len / 2; int lookouts; // 监视哨 while (d >= 1) { for (i = d; i < len; i++) { lookouts = arr[i]; for (j = i - d; j >= 0 && lookouts < arr[j]; j = j - d) { Swap_element(arr + j + d, arr + j); Comparisons_num++; } if (arr[j + d] != lookouts) { Swap_element(arr + j + d, &lookouts); Comparisons_num++; } } d /= 2; } }
-
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
-
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
先取一个len/2的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2=d1/2,重复上述的分组和排序,直至所取的增量 =1( < … 直接选择排序的算法: 程序采用双层嵌套循环,外循环按顺序每次选择一个待排序的元素,内循环每次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。 堆分为大根堆和小根堆,是完全二叉树。 堆排序的算法: 归并排序采用了分治法,将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。 归并排序的算法通常用递归实现,先把待排序区间[s, e]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s, e]。 其算法如下: 最后是实现打印信息的函数:正序输出函数Print_sort_positive()、逆序输出函数Print_sort_negative()和显示移动次数和比较次数函数Print_mob_com()。 编写测试程序的文件use_sort.c,并比较七种排序的结果,如下图: 其中移动和比较次数最多的排序方法为冒泡排序,而移动次数最少的则是快速排序,比较次数最少为希尔排序。。 // 冒泡排序
void Bubble_sort(int *arr, int len)
{
int i, j;
int flag = 1; // 标记循环过程是否进行过交换,如果为1则进行了交换
for (i = 0; i < len && flag; i++)
{
flag = 0;
for (j = 1; j < len - i; j++)
{
if (arr[j - 1] > arr[j])
{
Swap_element(arr + j, arr + j - 1);
flag = 1;
}
Comparisons_num++;
}
}
}
// 分隔(快速排序)
int Division(int *a, int left, int right)
{
int base = a[left];
while (left < right)
{
while (left < right && base < a[right])
{
right--;
Comparisons_num++;
}
a[left] = a[right];
Mobile_num++;
while (left < right && a[left] < base)
{
left++;
Comparisons_num++;
}
a[right] = a[left];
Mobile_num++;
}
a[left] = base;
return left;
}
// 快速排序
// left 和 count初始值为0 right 初始值为数组长度 - 1
void Quick_sort(int *arr, int left, int right, int count)
{
int i;
int count_temp = count + 1;
if (left < right)
{
i = Division(arr, left, right);
Quick_sort(arr, left, i - 1, count_temp);
Quick_sort(arr, i + 1, right, count_temp);
}
}
// 选择排序
void Select_sort(int *arr, int len)
{
int i, j;
int tmp; // 记录待排序元素的下标
for (i = 0; i < len - 1; i++)
{
tmp = i;
for (j = i + 1; j < len; j++)
{
if (arr[tmp] > arr[j])
tmp = j;
Comparisons_num++;
}
if (tmp != i)
Swap_element(arr + tmp, arr + i);
}
}
// 构成堆 (堆排序)
void Heap_adjust(int arr[], int parent, int len)
{
int child;
int temp;
for (temp = arr[parent]; 2 * parent + 1 < len; parent = child)
{
child = 2 * parent + 1;
if (child < len - 1 && arr[child + 1] > arr[child])
{
child++;
Comparisons_num++;
}
Comparisons_num++;
if (temp < arr[child])
{
Swap_element (arr + child, arr + parent);
}
else
break;
}
}
// 堆排序
void Heap_sort(int arr[], int len)
{
int i;
for (i = (len - 1) / 2; i >= 0; i--)
Heap_adjust(arr, i, len);
for (i = len - 1; i > 0; i--)
{
Swap_element(arr, arr + i); // 每次将最大的数排在最后
Heap_adjust(arr, 0, i); // 重新构成堆,将最大的数放在第一位
}
}
// 归并 (归并排序)
void Merge(int arr[], int target[], int start, int mid, int end)
{
int i, j, k;
for (i = mid + 1, j = start; start <= mid && i <= end; j++)
{
if (arr[start] < arr[i])
target[j] = arr[start++];
else
target[j] = arr[i++];
Mobile_num++;
Comparisons_num++;
}
if (start <= mid)
{
for (k = 0; k <= mid - start; k++)
{
target[j + k] = arr[start + k];
Mobile_num++;
}
}
if (i <= end)
{
for (k = 0; k <= end - i; k++)
{
target[j + k] = arr[i + k];
Mobile_num++;
}
}
}
// 归并排序
// start 和 count初始值为0 end 初始值为数组长度 - 1
void Merge_sort(int arr[], int target[], int start, int end, int count)
{
int mid;
int count_temp = count + 1;
int * temp_arr = (int *)calloc(end + 1, sizeof(int));
if (start == end)
{
target[start] = arr[start];
Mobile_num++;
}
else
{
mid = (start + end) / 2;
Merge_sort(arr, temp_arr, start, mid, count_temp);
Merge_sort(arr, temp_arr, mid + 1, end, count_temp);
Merge(temp_arr, target, start, mid, end, count_temp);
}
if (count == 0)
{
free(temp_arr);
}
}
// 显示打印
// 正序输出
void Print_sort_positive(int *arr, int len)
{
int i;
for (i = 0; i < len; i++)
{
if (i % 10 == 0 && i != 0)
putchar('\n');
printf("%3d ", arr[i]);
}
putchar('\n');
}
// 逆序输出
void Print_sort_negative(int *arr, int len)
{
int i;
for (i = 0; i < len; i++)
{
if (i % 10 == 0 && i != 0)
putchar('\n');
printf("%3d ", arr[len - i - 1]);
}
putchar('\n');
}
// 显示移动次数和比较次数
void Print_mob_com()
{
printf("移动次数:%d\n", Mobile_num);
printf("比较次数:%d\n\n", Comparisons_num);
// 初始化
Mobile_num = Comparisons_num = 0;
}
#include "Sort.h"
#include