十种经典排序算法
来源:互联网 发布:手机淘宝店铺模板复制 编辑:程序博客网 时间:2024/05/18 03:58
经典排序算法
冒泡排序
算法原理:冒泡算法在对n个数进行由小到大的排序时,进行n-1次循环,每次循环将相邻的两个数进行比较,将较大的换到最上面;这样,每一次循环都将未排序的数中最大的数换到最上面,就行泡泡一样往上冒,进行n-1次后,就排好了序。
算法过程:
1. 令输入数组为a[n],设m为已排好序的数的个数。m=0。
2. 令i从0到n-m-1,比较a[i],a[i+1],若a[i]>a[i+1],将它们交换。
3. m=m+1。若n-1=m,跳到第4步;否则回到第2步。(这里之所以为n-1=m是因为,n个数排列,若n-1个最大的数已经排好,那么整个数组就排好序了,不难理解。)
4. 终止。
C语言描述:
void bubble_sort(int* a, int n){ int i, m=0;while(n-1>m){ for(i=0;i<n-m-1;++i){ if(a[i]>a[i+1]){ int temp = a[i]; a[i] = a[i+1]; a[i+1] = temp; } } m = m + 1; }}
复杂度分析:
T(n) = Θ(n²)
插入排序
算法原理:对于给定的n个数,从第二个数开始,将依次将每个数插入前面排好序的序列中恰当的位置,最后得到排好序的序列。
算法过程:
1. 输入乱序数组a[n](n个元素)。令i=1(从第二个数开始,数组索引从0开始)。
2. 令j=i(从当前位置开始往前插入)。
3. 若a[j-1]>a[j],将它们交换,并让j=j-1,继续执行这一步,直到j<=0。否则令i=1+1。
4. 若i==n则终止,否则跳回第2步。
C语言描述:
void insert_sort(int* a, int n){ int i; for(i=1;i<n;++i){ intj = i; while(a[j]<a[j-1]){ int temp = a[j]; a[j] = a[j-1]; a[j-1] = temp; j = j -1; } }}
复杂度分析:
T(n) = Θ(n²)
希尔排序
算法原理:希尔排序是改进的插入排序,之所以叫希尔排序是因为它是一个叫希尔的人提出的。希尔排序使用一个步长来划分子序列,使用插入排序给子序列排序,然后递减步长,再排序子序列,直到步长为1。步长初始值通常取为原序列长度的一半。
算法过程:
1. 输入序列a[n]。
2. 令步长step=n/2。划分出子序列a[0],a[step],a[2*step],·······。
3. 使用插入排序给子序列排序。
4. 递减步长,step=step-1。
5. 若step为0,则跳到6,否则跳到3。
6. 终止。
C语言描述:
void shell_sort(int* a, int n){ int step= n / 2; while(step >= 1){ int i= step; while(i < n){ intj = i; while(j >= step && a[j] < a[j - step]){ intt = a[j]; a[j]= a[j - step]; a[j- step] = t; j-= step; } i+= step; } step-= 1; }}
复杂度分析:
T(n) = Θ(nlogn)
选择排序
算法原理:在对n个数进行排列时,进行n-1次循环,每次循环选出剩下的数中最小的一个,将它加入到已排好序的序列后面。
算法过程:
1. 输入乱序数组a[n]。令i=0。
2. 令m=i,j=m+1。
3. 若a[m]>a[j],令m = j,j=j+1。重复这一步,直到j==n-1。
4. 将a[i]与a[m]进行交换。若i<n-1,i=i+1,跳回2;否则跳到5。
5. 终止。
C语言描述:
void select_sort(int *a, int n){ inti,j,m; for(i=0;i<n-1;++i){ inttemp; m =i; for(j=i+1;j<n;++j) if(a[m]>a[j]) m = j; temp = a[i]; a[i] = a[m]; a[m] = temp; }}
复杂度分析:
T(n) = Θ(n²)
快速排序
算法原理:快速排序是一个迭代循环的过程。每一次迭代,它随机选取一个数作为关键数,然后将所有小于它的数放在它的左边,大于的位于右边。然后将左边和右边的数迭代进行快速排序,最后得到排好序的序列。
算法过程:
一趟快速排序的过程:
1. 设输入数组a[n],low,high。low标记左边的索引,high标记右边的索引。
2. 令i=low,j=high,key=a[i]。
3. 若a[j]<key,交换a[i]和a[j],此时key值在a[j]中。否则j=j-1,重复这一步。
4. 若a[i]>key,交换a[i]和a[j],此时key值在a[i]中。否则i=i+1,重复这一步。
5. 若i==j,跳到6,否则跳到3。
6. 一趟快速排序终止。
C语言描述:
void quick_sort(int *a, int low, int high){ int i =low; int j =high; int key =a[i]; if (low>= high) return; while (i!= j){ while(a[j] >= key && j > i) j =j - 1; a[i] =a[j]; a[j] =key; while(a[i] <= key && i < j) i =i + 1; a[j] =a[i]; a[i] =key; } quick_sort(a,low, i - 1); quick_sort(a,i + 1, high);}
复杂度分析:
T(n) = Θ(nlogn)
归并排序
算法原理:归并排序是算法中分治法应用的典型。它将要排序的序列分为两部分,将这两部分分别排好序后,可以以O(n)时间复杂度将两个部分整合。两个部分的排序也可以使用归并排序,从而迭代得到结果。
算法过程:
合并过程:
1. 输入数组a[n],low、middle、high。合并的两个部分的索引范围为[low,middle),[middle,high)。
2. 定义一个临时数组temp[m],m=high-low。
3. 设置两个指针i,j分别指向两个部分的起始位置low,middle。
4. 比较a[i],a[j]将较小的放入数组temp,并递增相应指针。
5. 重复第4步直到两个部分所有的数都放入temp数组。
6. 将temp数组的所有内容复制到a[n]中[low,high)的相应位置。
完整迭代过程:
1. 输入数组a[n],low、high指示索引范围[low,high)。
2. 若high-low<2,说明只有一个元素,终止迭代,返回。否则到3。
3. 令middle=low+(low+high)/2。
4. 迭代a[n],low,middle。
5. 迭代a[n],middle,high。
6. 合并a[n],low,middle,high。
7. 终止。
C语言描述:
void merge(int* a, int n1, int n2, int n3){ int i =n1; int j =n2; int k =0; int* temp= (int*)malloc(sizeof(int)*(n3 - n1)); while (i< n2 && j < n3){ if(a[i] < a[j]) temp[k++] = a[i++]; elsetemp[k++] = a[j++]; } while(i<n2) temp[k++]= a[i++]; while(j<n3) temp[k++]= a[j++]; for (k =0; k < n3 - n1; ++k) a[k+n1]= temp[k]; free(temp);}void merge_sort(int* a, int low, inthigh){//[low,high) intmiddle = low + (high - low) / 2; if (high- low < 2) return;//only one element merge_sort(a,low, middle); merge_sort(a,middle, high); merge(a,low, middle, high);}
复杂度分析:
T(n) = Θ(nlogn)
计数排序
算法原理:对于一个数,若知道比它小的数有多少个,那么就可以确定它的位置了。计数排序是对整数进行排序的算法。一个待排序序列中所有的数必然是在某一个范围内的。定义一个长度为这个范围长度的计数数组并初始化为0,对需排序序列进行一遍扫描,将数的大小作为数组的索引,将计数数组元素的值加1.然后再按索引顺序输出相应个索引值,则得到排好序的序列。此算法适宜对数值相对集中的序列进行排序。
算法过程:
1. 输入需排序数组a[n]。
2. 扫描一遍a[n],令small记录最小的数,big记录最大的数。
3. 令m=big-small+1,创建计数数组b[m],并初始化为0。
4. 遍历数组a[n],使b[a[i]-small] += 1。
5. 遍历数中b[n],依次在在数组a[n]中加入b[j]个j+samll。由于计数时使用的索引为a[i]-small,因此需要使用j+small还原。b[j]标记其个数。
6. 终止。
C语言描述:
void count_sort(int *a, int n){ int *b; int i, j,m; int small= a[0]; int big =a[0]; for (i =1; i < n; ++i){ if(a[i] < small) small = a[i]; if(a[i] > big) big = a[i]; } m = big -small + 1; b =(int*)malloc(sizeof(int)*m); for (i =0; i < m; ++i) b[i] = 0; for (i =0; i < n; ++i) b[a[i]- small] += 1; j = 0; for (i =0; i < m; ++i){ while(b[i] > 0){ a[j++]= i + small; b[i]-= 1; } } free(b);}
负杂度分析:
T(n) = Θ(n)
堆排序
算法原理:
堆:堆分为最大堆和最小堆,是一种特殊的完全二叉树,特点是:它的根节点比其他所有节点都要小(最小堆)或大(最大堆),而它的左右子树也是最小堆或最大堆。按照从上到下,从左到右,分层地依次存入数组的话,节点a[i]的左子节点为a[2i+1],右子节点为a[2i+2]。
数组的堆化:是指对不符合堆标准的数组进行调整使其符合堆标准的过程。一种方法是从最后一个元素到第一个元素,将其与其父节点进行比较,若比父节点小(或大)则交换它们,一直比较到根节点。
堆的删除:堆的删除是指移除根节点,并将最后一个元素作为根节点,然后重新调整数组为堆的过程。
堆的调整:堆的调整是指删除堆以后对数组进行的调整,使其符合堆的标准的过程。一种方法是从根节点开始,将其与较小(或大)的子节点进行比较,若比子节点大,则交换它们,一直比较交换直到到了叶子节点或者交换条件不成立。
堆排序:对需排序的数组进行堆化,然后不断删除堆,调整堆,直到堆为空。将堆删除的节点依次收集得到排好序的序列。这个方法就称为堆排序。
算法过程:
1. 初始化堆,即将输入数组a[n]堆化。
2. 定义临时数组b[n]。
3. 执行堆的删除操作,将删除的节点加入到b[n]中。
4. 将删除节点后的堆进行调整。
5. 若堆不为空,回到3。
6. 输出数组b[n]。
7. 终止。
C语言描述:
void heap_init(int* a, int n){ int i; for (i =n - 1; i > 0; --i){ int j= i; while(j > 0){ intp; inttemp; if(j % 2) p = (j - 1) / 2;//左节点 elsep = (j - 2) / 2;//右节点 if(a[j] < a[p]){ temp= a[p]; a[p]= a[j]; a[j]= temp; } j =p; } }}void heap_adjust(int *a, int n){ int i =0; while (i< n){ int c= i; int l= 2 * i + 1 < n ? 2 * i + 1 : i; int r= 2 * i + 2 < n ? 2 * i + 2 : i; int j= a[l] < a[r] ? l : r; if(a[i] <= a[j]) break; else{ inttemp = a[i]; a[i]= a[j]; a[j]= temp; i =j; } }}int heap_delete(int *a, int n){ int e =a[0]; a[0] =a[n - 1]; heap_adjust(a,n - 1); return e;}void heap_sort(int* a, int n){ int i =n, j = 0; int* b =(int*)malloc(sizeof(int)*n); heap_init(a,n); while (i> 0) b[j++]= heap_delete(a, i--); for (i =0; i < n; ++i) a[i] =b[i]; free(b);}
负责度分析:
T(n) = Θ(n)
桶排序
算法原理: 一个序列的数,必然是在某一个范围内的,这个范围由最小的数与最大的数决定。桶排序将这个范围细分为多分区间,这些区间称为桶。在对一个序列进行排序时,将数放入相应的桶中,若桶中有多个数则该桶再次进行桶排序,最后从小到大依次出桶,就得到排好序的序列了。
算法过程:
1. 输入数组a[n],定义桶数组t[n]。需要注意的是,数组t[n]是一个元素为数组的数组,当然,也可以说是元素为容器的数组,因为每个元素都可能容纳若干数。
2. 遍历数组a[n],得到最小的数为small,最大的位high。
3. 令len=(high – small)/n。len记录细分区间的长度。
4. 遍历数组a[n]。令j=(a[i]-small)/len。将a[i]放入桶t[j]。
5. 顺序遍历桶数组t[n],若桶t[j]只包含一个数则将其出桶,否则将该桶进行桶排序(实现为迭代)后出桶。
6. 终止。
C语言描述:
最小堆排序:
void bucket_sort(int *a, int n){ int i, j; intlen;//区间长度 int**bucket;//桶数组 int*elems;//桶容量数组 int num =n + 1;//桶个数 int small= a[0]; int big =a[0]; if (n ==2){//只有两个元素,排列好后返回 if(a[0] > a[1]){ inttemp = a[0]; a[0]= a[1]; a[1]= temp; } return; } for (i =0; i < n; ++i){//找出最大最小值 if(a[i] < small) small = a[i]; if(a[i] > big) big = a[i]; } if (big== small) return;//所有元素相同,直接返回,若没有这句,将导致出桶时无限迭代 len =(big - small) / n + 1; elems = (int*)malloc(sizeof(int)*num); for (i =0; i < num; ++i) elems[i]= n / 5 + 2; bucket =(int**)malloc(sizeof(int*)*num); for (i =0; i < num; ++i){ bucket[i]= (int*)malloc(elems[i]*sizeof(int));//为桶分配空间,至少有两个元素的空间 bucket[i][0]= 0;//第一个元素记录有多少个数入桶 } for (i =0; i < n; ++i){//入桶 j =(a[i] - small) / len; bucket[j][0]+= 1; if(bucket[j][0] >= elems[j]){//桶空间不足,重新分配 intk; elems[j]*= 2; int*temp = (int*)malloc(sizeof(int)*elems[j]); for(k = 0; k < bucket[j][0]; ++k) temp[k]= bucket[j][k]; free(bucket[j]); bucket[j]= temp; } bucket[j][bucket[j][0]]= a[i]; } for (i =0, j = 0; i < num; ++i){//出桶 if(bucket[i][0] == 0) continue; elseif (bucket[i][0] == 1) a[j++]= bucket[i][1]; else{//桶元素有多个,迭代 intk; intm = bucket[i][0]; int*p = &bucket[i][1]; bucket_sort(p,m); for(k = 0; k < m; ++k) a[j++]= p[k]; } } free(elems); for (i =0; i < n; ++i) free(bucket[i]); free(bucket);}
复杂度分析:
T(n) = Θ(n)
基数排序
算法原理:基数排序是一种针对整数的排序,它可以看做是一种特殊的桶排序,使用0-9共10个桶。基数排序分为两种:LSD(least significant digital)和MSD(most significant digital)。LSD从数的最低位(即个位)开始,将数依次放入对应的桶中,然后依次出桶,再按数的下一位为基准依次入桶,然后依次出桶,直到最高位为止。MSD与LSD相仿,不过是从数的最高位开始,到最低位止,并且入桶后并不立刻出桶,而是以桶内的数为序列,以下一位为基准,再次进行基数排序。基数排序一般用于整数排序,但也可以用于浮点数,不过算法需要进行一些改变。
算法过程:
LSD:
1. 输入数组a[n]。遍历数组,得出最大的数,其位数为m。
2. 令i为数的当前基准位数。i=1。
3. 以数的第i位为基准依次入桶。
4. 依次出桶。i=i+1。若i>m,跳到5,否则重复3,4。
5. 终止。
MSD:
1. 输入数组a[n]。遍历数组得到最大的数,其位数为m。
2. 令i为数的当前基准位数。i=m。
3. 以数的第i位为基准入桶。i=i-1。
4. 若i>0,以各桶内的数为输入序列,分别跳到3。(此处应为实现为迭代)。
5. 依次出桶,得到最后排好序的序列。
6. 终止。
C语言描述:
LSD:
#define getbit(n,b) ((int)(n/pow(10, b-1))%10)void radix_sort(int* a, int n){ int i; int* len; int*bucket[10]; int bits= 1, big = a[0]; for (i =1; i < n; ++i) if(a[i]>big) big = a[i]; while (big/ (int)(pow(10, bits))) bits+= 1;//位数 len =(int*)malloc(sizeof(int) * 10);//分配空间 for (i =0; i < 10; ++i) len[i]= n / 5 + 2; for (i =0; i < 10; ++i){ bucket[i]= (int*)malloc(sizeof(int)*len[i]); } i = 0; while(++i <= bits) { int j,h; for (j= 0; j < 10; ++j)//重置桶 bucket[j][0]= 0; for (j= 0; j < n; ++j){//入桶 intb = getbit(a[j], i); bucket[b][0]+= 1; if(bucket[b][0] >= len[b]){ intk; len[b]*= 2; int*t = (int*)malloc(sizeof(int)*len[b]); for(k = 0; k < bucket[b][0]; ++k) t[k]= bucket[b][k]; free(bucket[b]); bucket[b]= t; } bucket[b][bucket[b][0]]= a[j]; } h = 0; for (j = 0; j < 10; ++j){//出桶 intk; for(k = 1; k <= bucket[j][0]; ++k) a[h++]= bucket[j][k]; } } free(len); for (i =0; i < 10; ++i) free(bucket[i]);}
复杂度分析:
T(n) = Θ(n)
注:
1. logn表示log₂n
- 十种经典排序算法
- JavaScript实现十种经典排序算法(js排序算法)
- 十大经典排序算法
- 十大经典排序算法
- 十大经典排序算法
- 十大经典排序算法
- 十种经典算法
- Java十大经典基础排序算法
- 十大经典排序算法总结
- JavaScript十大经典排序算法
- 十大经典排序算法(一)
- JavaScript十大经典排序算法
- JS的十大经典算法排序 》》
- JavaScript 十大经典排序算法
- JavaScript十大经典排序算法
- 十大经典排序算法js实现
- 十大经典排序算法小结
- 十大经典排序算法小结
- Ubuntu 14.04 安装 Sublime Text 3
- 键盘上的快捷键知多少
- 滴滴快的笔试题:最长和为零的子数组
- c++ set
- org.springframework.orm.hibernate3.HibernateSystemException: a different object with the same identi
- 十种经典排序算法
- SQL Server数据库删除行问题
- C++读取多行数字然后读取该行各个数字
- 美团网16年研发类校招面试经历
- Java环境变量配置
- Android 基础1
- 278-e-First Bad Version
- 结构体与位域的对齐:
- 求数组中最大和为零的子串 滴滴打车2016笔试题目