排序算法
来源:互联网 发布:php class实例化 编辑:程序博客网 时间:2024/06/01 13:27
总结
稳定 时间复杂度 平均时间复杂度 空间复杂度
冒泡排序 √ O(n2) O(n2) O(1)
选择排序 × O(n2) O(n2) O(1)
插入排序 √ O(n2) O(n2) O(1)
二叉排序 √/× O(n2) O(n*log2n) O(n)
快速排序 × O(n2) O(n*log2n) O(log2n )~O(n)
基数排序 √ O(n*logrm) O(n*logrm) O(2r) 【注】r为基数,m为堆数
希尔排序 × O O O(1)
堆排序 × O(n*log2n) O(n*log2n) O(1)
归并排序 √
锦标赛排序,类似于二叉树排序。
冒牌排序
for (int i = 0; i < size - 1; i++) { for (int j = 0; j < size - i - 1; j++) { if (array[j+1] < array[j]) { int tmp = array[j+1]; array[j+1] = array[j]; array[j] = tmp; } } }
选择排序
//每次选择最小的一个元素,进行位置交换。void select_sort(int array[], int size){ int i, j, tmp; for (i =0; i < size-1; i++ ) { index = i; for (j = i+1; j < size; j++) { //选择剩余元素中最小的一个元素,记录在index中 if (array[index] > array[j]) index = j; } if (i != index) { //进行元素的交换 tmp = array[index]; array[index] = array[i]; array[i] = tmp; } }}
插入排序
//在一个已经有序的小序列基础上,一次插入一个元素。void insert_sort(int array[], int size){ int i, j, tmp; for (i = 1; i <= size; i++) { tmp = array[i]; //待插入的元素 j = i-1; //与已排序的数逐一比较大小,大于tmp时,该数移后 while ((j > 0) && (array[j] > tmp)) { array[j+1] = array[j]; j--; } array[j+1] = tmp; }}
快速排序
- 快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。
基本思想
- 先从数列中取出一个数作为基准数。
- 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
- 再对左右区间重复第二步,直到各区间只有一个数。
【注】:进行函数调用时,传入的参数为:quick_sort(data,0, size-1);
void swap(int *array, int x, int y){ int tmp = array[x]; array[x] = array[y]; array[y] = tmp;}int partition1(int *array, int start, int end) { int pos = (start + end) / 2; swap(array,pos,end); int key = array[end]; int i = start-1; for(int j=start;j<=end;++j){ if(array[j]<key){ swap(array,++i,j); } } swap(array,++i,end); return i;}int partition(int *array, int start, int end) { int pos = (start+end)/2; int low = start+1; int high = end; int key = array[pos]; swap(array, pos, start); while (low < high) { while (low < high && array[low] <= key) low++; while (low < high && array[high] > key) high--; if (low >= high) break; swap(array, low, high); } if (array[low] > key) { swap(array, start, low-1); return low-1; } else { swap(array, start, low); return low; }}void quick_sort(int *array, int start, int end){ if (start >= end) { return; } int pos = partition(array, start, end); quick_sort(array, start, pos-1); quick_sort(array, pos+1, end);}
二叉排序
//生成二叉排序树,然后将二叉树采用中序遍历重新对array赋值struct node{ int value; struct node *left; struct node *right;};struct node *new_node(int value){ struct node *new_node = (struct node*)malloc(sizeof(struct node)); if (node) { node->value = value; node->left = NULL; node->right = NULL; } return node;}void insert_to_tree(struct node *root, struct node *node){ struct node *tmp = root, *prev = tmp; while (tmp) { prev = tmp; if (tmp->value < node->value) { tmp = tmp->right; } else { tmp = tmp->left; } } if (prev->value < node->value) { prev->right = node; } else { prev->left = node; }}int binary_tree_sort(int array[], int size){ int i = 0; struct node *root = new_node(array[i]); struct node *node = NULL; struct stack *s = NULL; for (i = 1; i < size; i++) { node = new_node(array[i]); if (!node) { return 0; } insert_to_tree(root, node); } //中序遍历二叉树,重新填充数组 s = create_stack(); if (s == NULL) { printf("Create stack failed!\n"); return 0; } node = root; i = 0; while (node || !is_empty(s)){ while (node) { push(&s, node); node = node->left; } node = pop(&s); array[i] = node->value; node = node->right; i++; if (i >= size) { break; } } destroy_stack(&s); return (i <= size);}
基数排序
int find_max_num(int array[], int size){ int i = 0, max = 0; for (; i < size; i ++) { if (array[i] > max) { max = array[i]; } } return max;}int get_loop_times(int num){ int loop = 0, tmp = 0; do { tmp = num / 10; loop++; } while (tmp != 0); return loop;}//将数字分配到各自的桶中,然后按照桶的顺序输出排序结果void __radix_sort(int array[], int size, int loop){ //建立一组桶 int buckets[10][size] = {0}; /* 求桶的index的除数 如798 个位桶index = (798 / 1) % 10 = 8; 十位桶index = (798 / 10) % 10 = 9; 百位桶index = (798 / 100) % 10 = 7 */ int tmp_num = (int) pow(10, loop-1); int i, j, index, k; for (i = 0; i < size; i++) { index = (array[i] / tmp_num) % 10; for (j = 0; j < size; j++) { if (buckets[index][j] == 0) { buckets[index][j] = array[i]; break; } } } //将桶中的数,倒回到原有数组中 k = 0; for (i = 0; i < 10; i++) { for (j = 0; i < size; j++) { if (buckets[i][j] != 0) { array[k] = buckets[i][j]; buckets[i][j] = 0; k++; } } }}//从个位开始,向高位依次放入桶中,进行排序void radix_sort(int array[], int size){ //获取数组中的最大数 int max_num = find_max_num(array, size); //获取最大数的位数,次数也是再分配的次数 int loop_times = get_loop_times(max_num); int i = 0; //对每一位进行桶分配 for (i = 1; i <= loop_times; i++) { __radix_sort(array, size, i); }}
希尔排序
- 插入排序的一种,是针对直接插入排序算法的改进。本质上是一种分组插入排序法。
基本思想:
- 先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插人排序;
- 然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
代码实现
void shellPass(int *R,int n, int d){//希尔排序中的一趟排序,d为当前增量 int tmp; for(i=d+1; i<=n;i++) //将R[d+1..n]分别插入各组当前的有序区 if(R[i]<R[i-d]){ tmp=R[i]; j=i-d; //R[0]只是暂存单元,不是哨兵 do {//查找R[i]的插入位置 R[j+d] = R[j]; //后移记录 j=j-d; //查找前一记录 }while(j>0 && tmp < R[j]); R[j+d]=tmp; //插入R[i]到正确的位置上 } }} void shellSort(int *R, int n){ int increment = n; //增量初值,不妨设n>0 do { increment=increment/3 +1; //求下一增量 shellPass(R,increment); //一趟增量为increment的Shell插入排序 }while(increment>1)}
堆排序
堆:
- n个元素序列{k1,k2,...,ki,...,kn},当且仅当满足下列关系时称之为堆:
- 堆中某个节点的值总是不大于或不小于其父节点的值
- 堆总是一棵完全树(若树的高度为H,则1~H-1层节点的个数都达到最大值)
- 堆一般用数组来表示,假设节点的下标为i,则:
- Parent(i) : return Floor(i/2);
- Left(i): return 2*i + 1;
- Right(i): return 2*i + 2;
- 含有N个元素的堆A的高度为Floor(lgN)
基本思想:
- 堆是一个完全二叉树,故而其最下层的叶子节点是从左至右存在的
- 最小堆的建立:
- 先建立一个最小堆,然后依次进行如下操作:
- 将堆顶与 index交换,然后重新调整size为0~index-1的堆
- 重复以上操作,直到堆的大小为0
算法实现:
inline void swap(int *a, int num1, int num2){ int tmp = a[num1]; a[num1] = a[num2]; a[num2] = tmp;}/* 对该数进行下滤操作,直到该数比左右节点都小就停止下滤。 即对某个根节点的值进行位置下降调整,使该值比其左右子节点都小; 若该节点是叶子节点,则无法while循环 */void PercolateDown(int num[] , int index,int size) { int min;//最小指向下标 while (index * 2 + 1<size) { //若该节点有左子结点,则假设该节点为最小 min = index * 2 + 1; if (index * 2 + 2<size) {//若有右子节点,比较获得左右子节点的最小值 if (num[min] > num[index * 2 + 2]) { min = index * 2 + 2; } } if (num[index] < num[min]) {//当前的节点小于左右子节点,则循环结束 break; } else { Swap(num, index, min);//将当前节点与最小子节点进行交换 index = min;// 重设下标,继续对该节点进行下虑 } }// while }/* 建堆方法,只需线性时间建好; 建堆的结果:数组的第一个元素(即树根)是所有元素中的最小值,索引小于等于size/2-1的其它元素(即其它非叶子节点)的值都是其所在子树的最小值 */void BuildHeap(int num[] ,int size) { int i; //从最后一个非叶子节点开始,对每个非叶子节点进行最小根调整,保证每个根节点都是其子树中的最小值 for (i = size / 2 - 1; i >= 0; i--) { PercolateDown(num, i,size); }}void HeapSort(int num[] ,int size){ int i; int iLength=size; //建立小顶堆 BuildHeap(num,size); /* 堆排序-建立大顶堆,数组按由大到小排序 基本思路: 从数组的最后一个元素开始,将其与第一个元素交换,然后对该元素进行下虑操作 此时第一个元素总是当前堆的最小值。 */ for (i = iLength - 1; i >= 1; i--) { Swap(num, 0, i); size--; //每交换一次,将堆的规模减小一次 PercolateDown(num, 0, size);//将新的首元素下虑操作 } }
归并排序
工作原理
- 将序列每相邻两个数字进行归并操作,形成个序列,排序后每个序列包含两个元素
- 将上述序列再次归并,形成个序列,每个序列包含四个元素
- 重复步骤2,直到所有元素排序完毕
代码实现
递归实现
void merge_sort(int array[], unsigned int first, unsigned int last){ int mid = 0; if(first<last) { /*mid = (first+last)/2;*/ /*注意防止溢出*/ /*mid = first/2 + last/2;*/ /*mid = ((first & last) + (first ^ last) >> 1);*/ mid = ((first & last) + ((first ^ last) >> 1)); /*修正上一句优先级错误*/ merge_sort(array, first, mid); merge_sort(array, mid+1,last); merge(array,first,mid,last); }}
原地merge
void merge(int array[], int low,int mid,int high){ int j = mid+1, k = 0; while(j <= high) { if(array[j-1] < array[j]) break; tmp = array[j]; k = j-1; while ( k >= 0 && tmp < array[k]){ array[k + 1] = array[k]; k--; } array[k] = tmp; j++; }}
增加一个临时数组来merge
void merge(int array[], int low,int mid,int high){ int tmp_arr[high-low+1] = {0}; int i = low, j = mid+1, k = 0; while(i <= mid && j <= high){ if(array[i] < array[j]) { tmp_arr[k++] = array[i++]; } else { tmp_arr[k++] = array[j++]; } } while(i <= mid) tmp_arr[k++] = array[i++]; while(j <= high) tmp_arr[k++] = array[j++]; i = low, k = 0; while(i <= high) array[i++] = tmp_arr[k++];}
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- [深入浅出Cocoa]之消息(二)-详解动态方法决议(Dynamic Method Resolution)
- Eclipse中Maven插件的安装与配置
- Android 获取Keystore 的SHA
- 深入浅出NodeJS——内存控制
- poj1470-Closest Common Ancestors(LCA)
- 排序算法
- zoj2913
- 双目视觉测量系统设计中的一些注意事项
- Python函数式编程指南(二):函数
- TCP 建立连接的三次握手 和释放连接的四次挥手 图解
- Spring --- java定时器,Spring定时器和Quartz定时器
- LeetCode OJ - Implement strStr()
- python学习笔记(二)
- NO7 显式的终结方法