排序算法(c语言实现)
来源:互联网 发布:vr软件下载 编辑:程序博客网 时间:2024/04/29 16:06
作为一个程序猿,编写程序,排序算法算是最基本的了。这篇博客中,我尽量以最通俗易懂的语言,最简单的代码来讲清楚这些比较常见的排序算法。
好了,首先来看一下各种排序算法的效率和稳定性方面的总结(这张图很好,网上找的):
下面我就根据这张图来说明各种排序算法。
一.插入排序
1.直接插入排序
直接插入排序就是把后面的元素依次插入到前面的有序列中,(第一次以第一个元素为有序列),插入位置后面的元素后移。下面是代码.
#include<stdio.h>int main(){ int sqList[]= {1,3,6,7,2,4,4,0,9,8}; insertSortDirect(sqList,10); printArr(sqList, 10); return 0;}void insertSortDirect(int *sqList, int length){ int i; for(i = 1; i < length; i++)//第一次把下标为0的作为有序序列 { int temp = sqList[i]; int j; for(j = i; j > 0; j--) { if(sqList[j - 1] > temp) { sqList[j] = sqList[j - 1]; } else break; } sqList[j] = temp; }}void printArr(int *sqList, int length){ int i; for(i = 0; i < length; i++) { printf("%d ", sqList[i]); }}
2.shell排序
shell排序其实就是直接插入排序的扩展。举个例子,shell排序先将待排数组以3为间隔分为几个子数组,对这几个子数组进行直接插入排序,然后以2为间隔重复,最后以1为间隔重复(此时就是直接插入排序)。因为对基本有序的数组进行直接插入排序效率很高。下面是代码。
#include<stdlib.h>void shellInsert(int *sqList, int length, int increment){ int i; for(i = increment; i < length; i++) { int temp = sqList[i]; int j; for(j = i; j >= increment; j = j - increment)//不是把愿数组真的分为几个子数组,因为每一次的shellInsert的步长是固定的,所以可以这样 { if(temp < sqList[j - increment]) { sqList[j] = sqList[j - increment]; } else break; } sqList[j] = temp; }}void shellSort(int *sqList, int length1, int *dlta, int length2){ int i; for(i = 0; i < length2; i++) { shellInsert(sqList, length1, dlta[i]); }}void printArr(int *sqList, int length){ int i; for(i = 0; i < length; i++) { printf("%d ", sqList[i]); }}int main(){ int sqList[]= {1,3,6,7,2,4,4,0,9,8}; int dlta[] = {3, 2, 1}; shellSort(sqList, 10, dlta, 3); printArr(sqList, 10); return 0;}
扩展几个:
1.折半插入排序
在直接插入排序时,用二分查找法来寻找待插入的位置。
#include <stdio.h>void insertSortB(int *sqList, int length){ int i; for(i = 1; i < length; i++) { int temp = sqList[i]; int max = i - 1; int min = 0; while(min <= max) { int center = (max + min)/2; if( temp < sqList[center]) max = center - 1; else min = center + 1; } int j; for(j = i - 1; j >= max + 1; j--) { sqList[j + 1] = sqList[j]; } sqList[max + 1] = temp; }}void printArr(int *sqList, int length){ int i; for(i = 0; i < length; i++) { printf("%d ", sqList[i]); }}int main(){ int sqList[]= {1,3,6,7,2,4,4,0,9,8}; insertSortB(sqList, 10); printArr(sqList, 10); return 0;}
2.2-路插入排序
3.表插入排序
二.选择排序
1.直接选择排序
直接选择排序就是每次寻找最大(小)的元素位置,然后将此元素与紧跟在有序列后面的第一个元素交换。直到有序列等于数组长度。虽然有交换,但是是基于选择的。
#include<stdlib.h>void printArr(int *sqList, int length){ int i; for(i = 0; i < length; i++) { printf("%d ", sqList[i]); }}int selectMin(int *sqList, int low, int high){ int min = sqList[low]; int minLocation = low; int i; for(i = low; i < high; i++) { if(sqList[i] < min) { min = sqList[i]; minLocation = i; } } return minLocation;}void simpleSelectSort(int *sqList, int length){ int i; for(i = 0; i < length; i++) { int temp = sqList[i]; int minLocation = selectMin(sqList, i, length); sqList[i] = sqList[minLocation]; sqList[minLocation] = temp; }}int main(){ int sqList[]= {1,3,6,7,2,4,4,0,9,8}; simpleSelectSort(sqList, 10); printArr(sqList, 10); return 0;}
2.堆排序
堆排序也很简单,原理很容易懂,主要是循环的结束判断用到了完全二叉树的性质。其实二叉树的性质大家也不用死记硬背,用的时候画一颗树推一下就好了。下面是代码,很容易看懂。
#include<stdio.h>void print(int *sqList, int length){ int i; for(i = 0; i < length; i++) { printf("%d ", sqList[i]); }}//m为调整的开始点,n为m堆得节点的最大下标void heapAdjust(int *sqList, int i, int n){ int index = i; int temp = sqList[i]; i = 2 * i + 1; while(i <= n) { if(i + 1 <= n && sqList[i] < sqList[i + 1]) i++; if(temp >= sqList[i]) break; sqList[index] = sqList[i]; sqList[i] = temp; index = i; temp = sqList[i]; i = 2 * i + 1; }}//从倒数第二层的第一个元素开始依次向上,对每个节点进行调整// 0// / \// 1 2// / \ / \// 3 4 5 6// /// 7//所以构造最大堆时,调整函数的参数n可以一直是数组长度void creatHeap(int *sqList, int length){ int i; for(i = (length - 1) / 2; i >= 0; i--) heapAdjust(sqList, i, length - 1);}int main(){ int sqList[] = {65, 0, 78, 18, 4, 66, 97}; creatHeap(sqList, 7); int temp = sqList[0]; sqList[0] = sqList[6]; sqList[6] = temp; int i; for(i = 5; i >= 0; i--) { heapAdjust(sqList, 0, i); temp = sqList[0]; sqList[0] = sqList[i]; sqList[i] = temp; } print(sqList, 7);}
三.交换排序
1.冒泡排序
每趟冒泡的过程,就是不断交换相邻元素,以此把最大(小)的元素交换到有序列后面。
#include<stdlib.h>void printArr(int *sqList, int length){ int i; for(i = 0; i < length; i++) { printf("%d ", sqList[i]); }}void swap(int *sqList, int i, int j){ sqList[i] = sqList[i] + sqList[j]; sqList[j] = sqList[i] - sqList[j]; sqList[i] = sqList[i] - sqList[j];}void bubbleSort(int *sqList, int length){ int i; for(i = 0; i < length; i++) { int j; for(j = 0; j < length - i -1; j++) { if(sqList[j] > sqList[j + 1]) swap(sqList, j, j + 1); } }}int main(){ int sqList[]= {1,3,6,7,2,4,4,0,9,8}; bubbleSort(sqList, 10); printArr(sqList, 10); return 0;}
2.快速排序
快速排序就是每次选择一个元素,然后把比他大的放前面,比他小的放后面,他放中间。递归(或循环)直到子数组只有一个元素。
#include<stdlib.h>void printArr(int *sqList, int length){ int i; for(i = 0; i < length; i++) { printf("%d ", sqList[i]); }}int partition(int *sqList, int low, int high){ int temp = sqList[low]; while(low < high) { //第一个判断是边界的检验 while(low < high && sqList[high] >= temp) high--; sqList[low] = sqList[high]; while(low < high && sqList[low] <= temp) low++; sqList[high] = sqList[low]; } sqList[low] = temp; return low;}void quickSort(int *sqList, int low, int high){ if(low < high) { int mid = partition(sqList, low, high); quickSort(sqList, low, mid -1); quickSort(sqList, mid + 1, high); }}int main(){ int sqList[]= {1,3,6,7,2,4,4,0,9,8}; quickSort(sqList, 0, 9); printArr(sqList, 10); return 0;}
四.归并排序
归并排序是分治法应用的很好例子。所谓分治法,就是把原问题分为规模较小,问题一样的子问题,不断分割知道子问题很容易就解出,记录子问题的结果,然后合并为原问题的解。下面是代码,很容易就可以看懂其中的过程。
#include<stdio.h>void print(int *sqList, int length){ int i; for(i = 0; i < length; i++) { printf("%d ", sqList[i]); }}void merge(int *sqList, int first, int mid, int last, int *temp){ int m = first; int i = first; int j = mid + 1; while(i <= mid && j <= last) { if(sqList[i] < sqList[j]) { temp[m] = sqList[i]; i++; m++; } else { temp[m] = sqList[j]; j++; m++; } } if(i <= mid) { for(i; i <= mid; i++) { temp[m] = sqList[i]; m++; } } if(j <= last); { for(j; j <= last; j++) { temp[m] = sqList[j]; m++; } } for(i = first; i <= last; i++) sqList[i] = temp[i];}void mergingSort(int *sqList, int begin, int end, int *temp){ if(begin == end) temp[begin] = sqList[begin]; else { int i = (begin + end) / 2; mergingSort(sqList, begin, i, temp); mergingSort(sqList, i + 1, end, temp); merge(sqList, begin, i, end, temp); }}int main(){ int sqList[] = {65, 70, 78, 18, 19, 66, 97}; int temp[7] = {}; mergingSort(sqList, 0, 6, temp); print(sqList, 7);}
五.基数排序
基数排序是基于多关键字的排序,k0,k1,k2,k3....kn,(一个关键字可以拆分为几个关键字,比如对数字排序,个十百可以分别作为关键字进行基数排序)。
基数排序可以分为两种:
1.从主关键字开始,即MSD基数排序
这种方法根据关键字的主次顺序依次把数组分为子数组,等到拆分到只剩最次关键字时,排序即可。
2.从最次关键字开始,即LSD基数排序。但对k i(0 <= i <= n - 1)排序时,只能用稳定的排序算法。
这种方法是从最次关键字开始,进行若干次分配,收集。下面以例子进行说明。
#include<stdio.h>/***这里用数组模拟链表*当然也可以使用真实的链表*//***对3位整数进行排序,则有三个关键字:个十百。*每个关键字的基数都是0-9,所以有3次分配收集的过程。*每一次分配,需要有一个包含10个元素的数组,用来记录每个基数对应的链表(逻辑上的)的头元素的开始下标*///求出数字的个十或百位的数字作为关键字//location取值为1,2,3.分别对应个十百int getKey(int data, int location){ int key; int i; for(i = 0; i < location; i++) { key = data % 10; data = data / 10; } return key;}typedef struct{ //因为data里包含了关键字数组,所以不用关键字数组了。 int data; int next;}SLCell;//分配的算法void distribute(SLCell *sqList, int length, int *baseBegin, int *baseEnd, int keyLocation){ int key;//key其实也是这个数在base数组中的下标 int i; for(i = 0; i < length; i++) { key = getKey(sqList[i].data, keyLocation); if(baseBegin[key] == -1) { baseBegin[key] = i; baseEnd[key] = i; } else { sqList[baseEnd[key]].next = i; baseEnd[key] = i; } }}//收集的算法void collect(SLCell *sqList, int length, int *baseBegin){ int index = 0; SLCell sqCell; SLCell sqListTemp[1000];//c不能声明为length长度 int i; for(i = 0; i < 10; i++) { if(baseBegin[i] != -1) { int flag = 1; sqCell = sqList[baseBegin[i]]; baseBegin[i] = -1;//为下一次重新分配做好准备(还原) while(flag == 1) { sqListTemp[index].data = sqCell.data; sqListTemp[index].next = -1;baseBegin[i] index++; if(sqCell.next == -1) flag = 0; else sqCell = sqList[sqCell.next]; } } } for(i = 0; i < length; i++) { sqList[i].data = sqListTemp[i].data; sqList[i].next = -1; }}int main(){ ///////////////////////////////////// //构造一个待排序的链表 SLCell sqList[11] = {}; int datas[] = {789, 123, 780, 123, 345, 321, 124, 98, 567 , 190,111}; int i; for(i = 0; i < 11; i++) { sqList[i].data = datas[i]; sqList[i].next = -1; } int baseBegin[10] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; int baseEnd[10] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; for(i = 1; i <= 3; i++) { distribute(sqList, 11, baseBegin, baseEnd, i); collect(sqList, 11, baseBegin); } for(i = 0; i < 11; i++) { printf("%d ", sqList[i]); }}
- 计数排序算法(C语言实现)
- 冒泡排序算法(C语言实现)
- 堆排序算法(c 语言实现)
- 排序算法(c语言实现)
- 排序算法集锦(c语言实现)
- 快速排序算法(C语言实现)
- 排序算法(C语言实现)
- C语言排序算法实现
- 排序算法--C语言实现
- c语言实现各种排序算法(作业:点名册排序)
- 归并排序的实现(排序算法c语言描述)
- 排序算法之插入排序(C语言实现)
- 排序算法之希尔排序(C语言实现)
- 排序算法之选择排序(C语言实现)
- 排序算法-合并排序(C语言实现)
- C语言实现排序算法---希尔排序
- 常用的各种排序算法(C语言实现)
- 几个基本排序算法总结( C语言实现 )
- android实现图片模糊背景效果
- Prime Ring Problem (HDU 1016)—— 回溯法
- HDU 1018
- 该死的“代码就是文档”
- android仿安卓微信、云播雷达扫描动画效果
- 排序算法(c语言实现)
- 使用POI导出EXCEL 并设置格式
- NYOJ-蛇形填数
- android带彩色下划线的tab移动导航
- Android 新建一个草稿,保存,然后全部删除会话,关机再开机后还会显示保存的草稿
- Linux安装配置php
- JDKBIN目录下的命令
- cocos2d之音乐和音效
- Android 当输入联系人并编辑彩信后,切换语言,输入的联系人会消失