简单排序算法之插入排序、选择排序和冒泡排序
来源:互联网 发布:ps软件教学 编辑:程序博客网 时间:2024/06/02 02:59
倒也不是临时起意,被问了冒泡排序,我竟然……忘了,好吧,时隔多年重见冒泡,好久不见 甚是想念;
于是乎就写了下代码,顺便重温了两个简单的排序算法:插入排序和选择排序;
作为一个开头,之后有机会就把其它相关排序也总结下,不得不说,真的好生疏/(ㄒoㄒ)/~~
简单排序算法之插入排序、选择排序和冒泡排序
插入排序:
插入排序是从无序区里依次拿到元素放到有序区里合适的位置;
选择排序;
选择排序是每次将无序区里的最小值放到有序区里的最后一个位置;
冒泡排序;
冒泡排序是每次循环将最大的数“冒泡”到最上边;
有了这几个简单的描述,接下来让我们一个一个来看下;
1.插入排序:
插入排序是从无序区里依次拿到元素放到有序区里合适的位置;
1.1插入排序的理解:
可以将原来的数组看成两个区,分别用两个数组来表示,一个有序区,一个无序区;
有序区起始包含一个元素,即原数组的位置0所对应的元素;
无需区则包含剩余的所有元素;
我们遍历无需区元素,然后与有序区(从末尾位置)逐个进行比较,因为有序区有序,所以当找到满足比较大小的要求时对应的位置,就是元素要插到有序区对应的位置;
为此,我们还需要遍历有序区,好让遍历无序区的元素在有序区中找到合适的位置;
遍历无序区对应算法的外循环;
遍历有序区,比较出无序元素的位置对应内循环;
1.2我们看下具体实现的代码:
//插入排序/*数组 数组长度 数组元素的大小 比较函数指针*/int issort(void * data, int size, int esize, int (*compare)(const void * key1, const void * key2)){ char * a = data; void * key; int i, j; if ((key = (char *)malloc(esize)) == NULL) { return -1; } for (j = 1; j < size; j++) { memcpy(key, &a[j * esize], esize); i = j - 1; while (i >= 0 && compare(&a[i * esize], key) > 0) { memcpy(&a[(i + 1) * esize], &a[i * esize], esize); i--; } memcpy(&a[(i + 1) * esize], key, esize); for (int x = 0 ; x < size; x++) { printf("%i",a[x*esize]); } printf("\n"); } free(key); return 0;}
1.3这里需要注意c函数的使用:
#include <string.h>
void*
memcpy(void*restrictdst,constvoid*restrictsrc,size_tn);
使用时可以这样理解:由src指向地址为起始地址的连续n个字节的数据复制到以destin指向地址为起始地址的内存空间;
还要注意这一句:
memcpy(&a[(i + 1) * esize], &a[i * esize], esize);//这里之所以要乘以esize,是因为指针a的类型是char,要表示实际数组中的元素所占空间,需要乘以每个元素的大小;
1.4关于时间复杂度:
总的执行次数,可以这样推算:
原数组长度n
无需区长度j在遍历时逐渐变小直至0,分别为:(n-1),(n-2)……1;
对应相应的j值,在有序区需要遍历的次数i(我们只考虑最坏情况)则为:1,2,……(n-2),(n-1);
所有可以得到总的执行次数为(n -1 + 1)*(n - 1)/2 ,时间复杂度为O(n^2);即O(n的平方);
比较不同算法的时间复杂度可以通过下面这个:
O(n!) > O(3^n) > O(2^n) > O(n^3) > O(n^2lgn) > O(n^2) > O(nlgn) > O(n) > O(lgn) > O(1)
2.选择排序:
选择排序是每次将无序区里的最小值放到有序区里的最后一个位置;
说完了插入排序,再说选择排序就好说了;
2.1我们来看下代码;
//选择排序/*数组 数组长度 数组元素的大小 比较函数指针*/int chooseSort(void * data, int size, int esize, int (*compare)(const void * key1, const void * key2)){ char * a = data; void * key; int i, j, k; if ((key = (char *)malloc(esize)) == NULL) { return -1; } for (j = 0; j < size; j++) { i = j + 1; k = j; while (i < size ) { if (compare(&a[k * esize],&a[i * esize]) > 0) { k = i; } i++; } if (j != k) { memcpy(key, &a[j * esize], esize); memcpy(&a[j * esize],&a[k * esize] , esize); memcpy(&a[k * esize],key , esize); } for (int x = 0 ; x < size; x++) { printf("%i",a[x*esize]); } printf("\n"); } free(key); return 0;}
3.冒泡排序:
冒泡排序是每次循环将最大的数“冒泡”到最上边;
3.1直接看代码吧;
//冒泡排序/*数组 数组长度 数组元素的大小 比较函数指针*/int maopaoSort(void * data,int size, int esize,int (*compare)(const void * key1, const void * key2)){ char * a = data; void * key; int i ,j; if ((key = (char *)malloc(esize)) == NULL){ return -1; } for(i = 0; i < size;i++){ for(j = 0;j < (size - i -1);j++){ if(compare(&a[(j)*esize],&a[(j+1)*esize]) > 0){ memcpy(key, &a[(j) * esize], esize); memcpy(&a[(j) * esize], &a[(j+1) * esize], esize); memcpy(&a[(j+1) * esize], key, esize); } } for (int x = 0 ; x < size; x++) { printf("%i",a[x*esize]); } printf("\n"); } free(key); return 0;}
4.运行排序分析:
最后,我们来通过运行结果来分析和理解一下这几个算法的思想;
首先提供两个可用的比较函数:
//字符升序比较函数int compare(const void * key1, const void * key2){ char * keychar1 = (char * )key1; char * keychar2 = (char * )key2; return *keychar1 - *keychar2;}//数字升序比较函数int compare1(const void * key1, const void * key2){ int * keychar1 = (int * )key1; int * keychar2 = (int * )key2; return *keychar1 - *keychar2;}
之后,我们编写测试代码:
int ints1[] = {7,8,5,6,4,3}; for (int i = 0 ; i < 6; i++) { printf("%i",ints1[i]); } printf("\n"); printf("插入排序%i\n",issort(ints1,6,4,compare1)); printf("\n"); int ints2[] = {7,8,5,6,4,3}; for (int i = 0 ; i < 6; i++) { printf("%i",ints2[i]); } printf("\n"); printf("冒泡排序%i\n",maopaoSort(ints2,6,4,compare1)); printf("\n"); int ints3[] = {7,8,5,6,4,3}; for (int i = 0 ; i < 6; i++) { printf("%i",ints3[i]); } printf("\n"); printf("选择排序%i\n",chooseSort(ints3,6,4,compare1)); return 0;
如果是比较字符串,你也可以这样写:
char chars[] = "flower"; printf("%lu\n",sizeof(chars));//7 有一个\0空间 printf("%i\n",chooseSort(chars,6,1,compare));//传6 是因为不需要比较\0 printf("%s\n",chars);
我们看看这几个数字排序的log:
我们起始排序的数组都是{785643};
箭头表示的是每次排序之后的结果,以及数字位置的变化;(还是图说的比较清楚,文字就不再赘述了)
还需要说明的是,三个算法的时间复杂度都是O(n^2);
so,这几个排序算法就ok了,个人理解,希望对大家有帮助。
- Java简单算法之 冒泡排序 选择排序 插入排序
- 常用内部排序算法之四:简单选择排序、直接插入排序和冒泡排序
- 简单排序算法之选择排序、直接插入排序和冒泡排序
- (九)数据结构之简单排序算法实现:冒泡排序、插入排序和选择排序
- 简单排序算法之插入排序、选择排序和冒泡排序
- 简单排序算法:冒泡排序,选择排序,插入排序
- 简单排序算法(冒泡排序、选择排序、插入排序)
- 简单排序之冒泡排序,选择排序,插入排序
- 排序算法之“选择排序-冒泡排序-插入排序”
- 简单排序:冒泡排序、选择排序和插入排序
- 五、排序算法之简单算法——冒泡排序、简单选择排序和直接插入排序
- 经典排序算法之冒泡、选择和插入排序
- 【算法】插入排序/冒泡排序/选择排序
- 《算法》选择排序、插入排序、冒泡排序
- 简单排序算法:冒泡排序,选择排序和插入排序的c++实现
- java算法之冒泡排序、选择排序、插入排序
- 冒泡排序 选择排序和插入排序
- 冒泡排序、插入排序和选择排序
- 修改centos源为阿里云源
- 安卓逆向DDMS不显示待附加进程解决思路
- LeetCode(7) Given a 32-bit signed integer, reverse digits of an integer解题报告
- android图片裁剪拼接实现(一):Matrix基本使用
- git clone 异常现象
- 简单排序算法之插入排序、选择排序和冒泡排序
- 点击qq图标,弹出与其对话聊天的窗口
- seo技术也可以用于淘宝站内搜索
- 通用mapper 根据条件修改、查询 Example的实例函数及例子
- ArrayList的源码实现
- C编译: 动态连接库 (.so文件)
- 面向对象的六大原则
- Google引爆大数据时代的三篇论文
- PowerDesigner逆向工程导入MYSQL数据库