标签:
内部排序是指待排序列完全存放在内存中所进行的排序过程,适合不太大的元素序列。排序是计算机程序设计中的一种重要操作,其功能是对一个数据元素集合或序列重新排列成一个按数据元素某个相知有序的序列。排序分为两类:内排序和外排序。其中快速排序的是目前排序方法中被认为是最好的方法。内部排序方法: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 <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> #include <conio.h> #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<n; 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( < …<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
// 冒泡排序 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); } }
归并排序采用了分治法,将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
归并排序的算法通常用递归实现,先把待排序区间[s, e]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s, e]。
其算法如下:
// 显示打印 // 正序输出 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; }
最后是实现打印信息的函数:正序输出函数Print_sort_positive()、逆序输出函数Print_sort_negative()和显示移动次数和比较次数函数Print_mob_com()。
#include "Sort.h" #include <stdio.h> int main(void) { int arr[ARRAY_LEN]; int temp_arr[ARRAY_LEN]; int target_arr[ARRAY_LEN]; Create_data(arr, ARRAY_LEN, MIN, MAX); Copy_array(target_arr, arr, ARRAY_LEN); printf("排序前: \n"); Print_sort_positive(target_arr, ARRAY_LEN); Bubble_sort(target_arr, ARRAY_LEN); printf("\n完全正序: \n"); Print_sort_positive(target_arr, ARRAY_LEN); printf("\n完全逆序: \n"); Print_sort_negative(target_arr, ARRAY_LEN); // 开始进行七种排序比较 Copy_array(target_arr, arr, ARRAY_LEN); Bubble_sort(target_arr, ARRAY_LEN); printf ("冒泡排序:\n"); Print_mob_com(); Copy_array(target_arr, arr, ARRAY_LEN); Quick_sort(target_arr, 0, ARRAY_LEN - 1, 0); printf ("快速排序:\n"); Print_mob_com(); Copy_array(target_arr, arr, ARRAY_LEN); Copy_array(temp_arr, arr, ARRAY_LEN); Merge_sort(temp_arr, target_arr, 0, ARRAY_LEN - 1, 0); printf ("归并排序:\n"); Print_mob_com(); Copy_array(target_arr, arr, ARRAY_LEN); Heap_sort(target_arr, ARRAY_LEN); printf ("堆排序:\n"); Print_mob_com(); Copy_array(target_arr, arr, ARRAY_LEN); Insert_sort(target_arr, ARRAY_LEN); printf ("直接插入排序:\n"); Print_mob_com(); Copy_array(target_arr, arr, ARRAY_LEN); Select_sort(target_arr, ARRAY_LEN); rintf ("选择排序:\n"); Print_mob_com(); Copy_array(target_arr, arr, ARRAY_LEN); Shell_sort(target_arr, ARRAY_LEN); printf ("希尔排序:\n"); Print_mob_com(); return 0; }
编写测试程序的文件use_sort.c,并比较七种排序的结果,如下图:
其中移动和比较次数最多的排序方法为冒泡排序,而移动次数最少的则是快速排序,比较次数最少为希尔排序。。
七种机器内部排序的原理与C语言实现,并计算它们的比较次数与移动次数。
标签:
原文地址:http://www.cnblogs.com/hcxc/p/5647810.html