温故而知新 -> 数据结构 ->排序 ->程序实现1_利用C语言
2022/2/2 9:42:39
本文主要是介绍温故而知新 -> 数据结构 ->排序 ->程序实现1_利用C语言,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
温故而知新 -> 数据结构 ->排序 ->程序实现1_利用C语言
本篇博客是基于 温故而知新 -> 数据结构 ->排序 中部分 排序 的理论知识进行程序实现!
其中实现了 交换排序中的三种快速排序、递归与非递归的归并排序、非比较排序等!并附带了相关实例以及对应的运行结果!
由于上述的程序实现中使用了顺序表和队列,即还需实现顺序表与队列这两个内容,如此会导致程序代码量大幅增多。而在程序中,为了清晰展示各部分的实现代码,所以加上各自的头文件共有 5 个文件,即 queue.h
、seqList.h
、queue.c
、seqList.c
和 main.c
。
其中 queue.h
和queue.c
的内容与 温故而知新->数据结构->队列->程序实现1_利用结构体 博客中的 newQueue.h
和 main.c
对应且相同,但为方便本次程序的运行,需将上述博客的 main.c
中的 test()
与 main()
两个函数进行删除或注释;
而 seqList.h
和 seqList.c
的内容与 温故而知新->数据结构->顺序表->程序实现1_利用结构体 博客中的 seqList.h
和 main.c
对应且相同,也为方便本次程序的运行,需将上述博客的 main.c
中的 test()
与 main()
两个函数进行删除或注释。
在下述内容中将附上本次程序的 main.c
文件内容,其他文件内容可根据上述指引自行查看!
注意:下述代码多多少少有点冗余,且未考虑性能最优,读者有兴趣可进一步精简!
具体内容如下:
(1)main.c
#include<stdio.h> #include<stdlib.h> #include<time.h> #include<string.h> #include"seqList.h" #include"queue.h" void swap(int *arr, int a, int b) { int t = arr[a]; arr[a] = arr[b]; arr[b] = t; } //交换排序 之 冒泡排序 实现方法 void bubbleSort(int *arr, int n) { //相邻元素进行比较 //第一次遍历范围:0~未排序数据的最后一个位置 int m = n; while (m>1)//正常情况每次循环所运行步数 6 5 4 3 2 1 = 21 { //flag:标记一轮冒泡排序中是否发生了交换操作 int flag = 0; for (int j = 1; j < m; j++) { if (arr[j-1] > arr[j]) { swap(arr, j-1, j); flag = 1; } } //如果没有发生交换,说明剩余元素全部有序 -- 提高性能 if (!flag) break; m--; } /*for (int i = 0; i < n; i++) { for (int j = i; j < n; j++) { if (arr[j - 1] > arr[j]) { swap(arr, j - 1, j); } h++; } } printf("h = %d \n", h);*/ } //hoare改进:获取基准值:三数取中法 起始,中间,结束 int getMid(int *arr, int begin, int end) { int mid = begin + (end - begin) / 2; if (arr[begin] >= arr[mid]) { if (arr[mid] >= arr[end]) // arr[begin]>arr[mid]>arr[end] return mid; else if (arr[begin] <= arr[end])//arr[end]>arr[begin]>=arr[mid] return begin; else // arr[begin]>arr[end]>arr[mid] return end; } else//arr[begin] < arr[mid] { if (arr[mid] <= arr[end])//arr[begin] < arr[mid] <arr[end] return mid; else if (arr[begin] >= arr[end])//arr[end]<=arr[begin]<arr[mid] return begin; else //arr[end]<arr[begin]<arr[mid] return end; } } //交换排序 之 挖坑法 int partion2(int *arr, int begin, int end) { //获取基准值的位置 int mid = getMid(arr, begin, end); //把基准值放到起始位置 swap(arr, begin, mid); //第一个值作为基准值,第一个位置为初始的坑的位置 int key = arr[begin]; //int start = begin; while (begin < end) { //int key = start; //从后往前先找小于基准值的位置 while (begin < end && arr[end] >= key) --end; //填坑 arr[begin] = arr[end]; //从前往后找大于基准值的位置 while (begin < end && arr[begin] <= key) ++begin; //填坑 arr[end] = arr[begin]; } //相遇位置放入基准值 arr[begin] = key; return begin; } //交换排序 之 前后指针法 int partion3(int *arr, int begin, int end) { //上一个小于基准值的位置 int prev = begin; //下一个小于基准值的位置 int cur = begin + 1; int key = arr[begin]; while (cur <= end) { //当prev与cur不连续时,则交换此两个数,首先判断连续 if (arr[cur] < key && ++prev != cur)//不连续 { //不连续,交换两数数据 swap(arr, prev, cur); } ++cur; } //交换基准值与prev的值 swap(arr, begin, prev); return prev; } //交换排序 之 快速排序:hoare法 //返回划分之后,基准值所在的位置 int partion(int *arr, int begin, int end) { //获取基准值的位置 int mid = getMid(arr, begin, end); //把基准值放到起始位置 swap(arr, begin, mid); //选择基准值 int key = arr[begin]; int start = begin; while (begin < end) { //从后往前先找小于基准值的位置 while (begin < end && arr[end] >= key) --end; //从前往后找大于基准值的位置 while (begin < end && arr[begin] <= key) ++begin; //交换 swap(arr, begin, end); } //结束后交换基准值和相遇位置的数据 swap(arr, start, begin); return begin; } //递归快排 void quickSort(int *arr, int begin, int end)//hoare 的实现 { if (begin >= end) return; //div:一次划分之后,基准值位置 int div = partion3(arr, begin, end); //左右两部分进行快速排序 //[begin,div-1] //[div+1,end] quickSort(arr, begin, div - 1); quickSort(arr, div + 1, end); } /*非递归快排 用顺序表 */ void quickSortNor(int *arr, int n) { //创建一个顺序表,保存待划分的区间 SeqList sq; initseqList(&sq); //首先保存整个区间 //首先放右,再放左 seqListPushBack(&sq, n - 1); seqListPushBack(&sq, 0); //遍历顺序表,处理所有区间 while (!seqListEmpty(&sq))//非空才能进行程序运行!!!!!!!!!!! { //取出一个区间 int left = seqListBack(&sq); seqListPopBack(&sq); int right = seqListBack(&sq); seqListPopBack(&sq); //划分区间[left,right] int div = partion(arr, left, right); //保存产生的两个新区间 //[left,div-1] if (left < div - 1) { seqListPushBack(&sq, div - 1); seqListPushBack(&sq, left); } //[div+1,right] if (div + 1 < right) { seqListPushBack(&sq, right); seqListPushBack(&sq, div + 1); } } } /*非递归快排 用队列 */ void quickSortNor2(int *arr, int n) { //创建一个队列,保存待划分的区间 Queue q; initQueue(&q); //首先保存整个区间 队列:先进先出 //首先放右,再放左 queuePush(&q, 0); queuePush(&q, n - 1); //遍历队列,处理所有区间 while (!queueEmpty(&q))//非空才能进行程序运行!!!!!!!!!!! { //取出一个区间 int left = queueFront(&q); queuePop(&q); int right = queueFront(&q); queuePop(&q); //划分区间[left,right] int div = partion(arr, left, right); //保存产生的两个新区间 //[left,div-1] if (left < div - 1) { queuePush(&q, left); queuePush(&q, div - 1); } //[div+1,right] if (div + 1 < right) { queuePush(&q, div + 1); queuePush(&q, right); } } } //归并排序!!!!!!!!! //相邻子序列合并: begin end end+1 end2 void merge(int *arr, int begin, int mid, int end, int *tmp) { //递增 //子区间: [begin,mid] [mid+1,end] int begin1 = begin; int end1 = mid; int begin2 = mid + 1; int end2 = end; //辅助空间的起始位置 int idx = begin; //合并有序序列 while (begin1 <= end1 && begin2 <= end2) { if (arr[begin1] <= arr[begin2]) tmp[idx++] = arr[begin1++]; else tmp[idx++] = arr[begin2++]; } //判断是否有未合并的元素 if (begin1 <= end1) memcpy(tmp + idx, arr + begin1, sizeof(int)*(end1 - begin1 + 1)); if (begin2 <= end2) memcpy(tmp + idx, arr + begin2, sizeof(int)*(end2 - begin2 + 1)); //合并之后的序列拷贝到原始数据的对应区间 memcpy(arr + begin, tmp + begin, sizeof(int)*(end - begin + 1)); } //时间复杂度:o(nlogn) 稳定 /* 归并递归 */ void _mergeSort(int *arr, int begin, int end, int *tmp) { if (begin >= end) return; int mid = begin + (end - begin) / 2; //首先合并子序列 _mergeSort(arr, begin, mid, tmp); _mergeSort(arr, mid + 1, end, tmp); //合并两个有序的子序列 merge(arr, begin, mid, end, tmp); } void mergeSort(int *arr, int n)//递归 { //申请辅助空间 int *tmp = (int *)malloc(sizeof(int)*n); _mergeSort(arr, 0, n - 1, tmp); free(tmp); } /* 归并非递归 */ void mergeSortNor(int *arr, int n)//非递归 { int *tmp = (int *)malloc(sizeof(int)*n); //子序列的步长 int step = 1; while (step < n) { //先处理小的序列,再处理大的 for (int idx = 0; idx < n; idx += 2 * step) { //找到两个待合并的子序列区间 //[begin,mid] [mid+1,end] int begin = idx; int mid = idx + step - 1; //判断是否存在第二个子序列 if (mid >= n - 1) //不存在第二个子序列,直接跳过 continue; int end = idx + 2 * step - 1; //判断第二个子序列是否越界 if (end >= n) end = n - 1; merge(arr, begin, mid, end, tmp); } //更新步长 step *= 2; } //free(tmp); } //非比较排序 -- 计数排序 //时间复杂度:O(Max(n,range)) //空间复杂度:O(range) 若范围特别多,浪费空间巨大 如:0 1 2 10000000 void countSort(int *arr, int n) { //找到最大和最小值 int max, min; min = max = arr[0]; for (int i = 1; i < n; i++) { if (arr[i] > max) max = arr[i]; if (arr[i] < min) min = arr[i]; } //计算计数数组的个数范围 int range = max - min + 1; //创建一个计数数组,初始化为0 int *countArr = (int *)calloc(range,sizeof(int)); //计数 计算arr中相同数字的个数 for (int i = 0; i < n; ++i) { countArr[arr[i] - min]++; } //遍历计数数组,排序 int idx = 0; for (int i = 0; i < range; i++) { while (countArr[i]--) { arr[idx++] = i + min; } } } //打印数组 void printArr(int *arr, int n) { for (int i = 0; i < n; i++) { printf("%d ", arr[i]); }printf("\n"); } void test() { int arr1[] = { 6, 3, 1, 8, 7, 2, 4 }; int n = sizeof(arr1) / sizeof(arr1[0]); int *arr2 = (int*)malloc(sizeof(int)*n); memcpy(arr2, arr1, sizeof(arr1)); printf("排序前内容:\n"); printArr(arr2, n); printf("\n"); printf("冒泡排序后内容:\n"); bubbleSort(arr2, n); printArr(arr2, n); printf("\n"); memcpy(arr2, arr1, sizeof(arr1)); printf("递归快排后内容:\n"); quickSort(arr2, 0, n - 1); printArr(arr2, n); printf("\n"); memcpy(arr2, arr1, sizeof(arr1)); printf("非递归快排(利用顺序表)后内容:\n"); quickSortNor(arr2, n); printArr(arr2, n); printf("\n"); memcpy(arr2, arr1, sizeof(arr1)); printf("非递归快排(利用队列)后内容:\n"); quickSortNor2(arr2, n ); printArr(arr2, n); printf("\n"); memcpy(arr2, arr1, sizeof(arr1)); printf("递归归并排序后内容:\n"); mergeSort(arr2, n ); printArr(arr2, n);printf("\n"); memcpy(arr2, arr1, sizeof(arr1)); printf("非递归归并排序后内容:\n"); mergeSortNor(arr2, n); printArr(arr2, n); printf("\n"); memcpy(arr2, arr1, sizeof(arr1)); printf("非比较排序后内容:\n"); countSort(arr2, n); printArr(arr2, n); printf("\n"); memcpy(arr2, arr1, sizeof(arr1)); } //void test2() //{ // int n; // printf("数据量:\n"); // scanf_s("%d", &n); // srand(time(NULL)); // int *arr = (int *)malloc(sizeof(int)*n); // int *copy1 = (int *)malloc(sizeof(int)*n); // int *copy2 = (int *)malloc(sizeof(int)*n); // for (int i = 0; i < n; i++) // { // arr[i] = rand(); // } // memcpy(copy1, arr, sizeof(int)*n); // memcpy(copy2, arr, sizeof(int)*n); // // time_t begin = clock(); // insert(copy1, n); // time_t end = clock(); // printf("直接插入排序时间:%d\n", end - begin); // // begin = clock(); // shellSort(copy2, n); // end = clock(); // printf("希尔排序时间:%d\n", end - begin); //} int main() { test(); system("pause"); return 0; }
(2)运行结果
侵权删~
这篇关于温故而知新 -> 数据结构 ->排序 ->程序实现1_利用C语言的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-16在电脑上怎么模拟手机的运行环境?-icode9专业技术文章分享
- 2024-11-16接收socket数据,莫名其妙socket就关闭了是怎么回事?-icode9专业技术文章分享
- 2024-11-16ts nightly是什么?-icode9专业技术文章分享
- 2024-11-16如何升级vscode版本?-icode9专业技术文章分享
- 2024-11-16如何设置vscode默认的node版本?-icode9专业技术文章分享
- 2024-11-16shell 如何创建一个文件夹?-icode9专业技术文章分享
- 2024-11-16useReducer案例详解:从零开始理解与应用
- 2024-11-15聊聊用LangChain4J构建聊天机器人的那些事儿
- 2024-11-15LangChain 和 LlamaIndex 在检索增强生成(RAG)中的大比拼:全面对比评测
- 2024-11-15平台工程不只是配置管理:超越CFEngine的方法