算法基础--快排序,堆排序,归并排序
2016-05-11 18:33
260 查看
这是笔记;
快速排序的思想:先说一趟划分:一个数组a[0...(length-1)],把数组的第一个元素当作枢轴v(是vlaue,不是下标),将数组中所有比k小的元素都移动到k的左侧,将所有比v大的元素都移动到元素的右边。
我们需要得到一个数组划分后,枢轴v现在的位置下标(这是下一步进行划分的边界);
长度为n的数组,平均需要log(n)次划分。
代码实现:
堆排序:
堆排序思想:
什么大根堆?完全二叉树中的每个节点元素 大于等于 它的孩子节点值 ;左右孩子节点间没有任何关系
我们首先需要将一个数组a[]按照大根堆的标准建堆,
(1) 建好堆---》将数组a的第一个元素和最后一个元素调换,-----》再修复堆
步骤(1) 我们需要迭代size(a)-1次,才能排好序。
这个思想很重要,因为 它能在一趟排好序的过程中,能在O(n)时间内建好堆; 但是建好堆后,对剩余的(n-i)的每个元素在log(n-i)时间内完成排序了;
代码:
梳理一边数组建堆的过程:
建堆也是不断调堆Shift的过程,shift(int a[],int i,int m)函数所作的工作就是将数组a[i...m] (都是下标)。
归并排序:
归并排序思想:
代码:
快速排序的思想:先说一趟划分:一个数组a[0...(length-1)],把数组的第一个元素当作枢轴v(是vlaue,不是下标),将数组中所有比k小的元素都移动到k的左侧,将所有比v大的元素都移动到元素的右边。
我们需要得到一个数组划分后,枢轴v现在的位置下标(这是下一步进行划分的边界);
长度为n的数组,平均需要log(n)次划分。
代码实现:
///quick sort void quick_sort(int a[],int s,int t){//这是算法的开始,我们看到,输入s\t都是下标,下标和长度从一开始一定要区分开 if(s<t){///那么这个算法什么时候结束呢?这是一个很常见的问题?----------》只要可划分数组a[]的长度大于1,就是说s<t,我们就对它进行划分。 int k = Partition(a,s,t);///一趟划分,返回下一次划分的边界,这个k上的元素就排好了。我们可以利用了这个性质,做很多有意义的事情。,比如找到数组a中最小的k个数字; quick_sort(a,s,k-1); quick_sort(a,k+1,t); } } int Partition(int a[],int s,int e){///这就是划分算法,下面的while很经典。 int temp = a[s];///store the a[s] ,先创建一个临时变量来保存当前位置的元素值。 while(s<e){///只要多于一个元素,我们就运行划分算法 while(s<e && a[e]>=temp) e--;///从数组的后面向前开始找,先找第一个小于tmp的元素--> a[s] = a[e];///-->将这个元素与a[s]交换 while(s<e && a[s]<=temp) s++;///从数组的前面向后开始找第一个大于tmp的元素 a[e] = a[s];///将这个元素和a[s]交换 }///while a[s] = temp;///将tmp值放到最终的位置上, return s;///返回找到元素的下标 }//Partition
堆排序:
堆排序思想:
什么大根堆?完全二叉树中的每个节点元素 大于等于 它的孩子节点值 ;左右孩子节点间没有任何关系
我们首先需要将一个数组a[]按照大根堆的标准建堆,
(1) 建好堆---》将数组a的第一个元素和最后一个元素调换,-----》再修复堆
步骤(1) 我们需要迭代size(a)-1次,才能排好序。
这个思想很重要,因为 它能在一趟排好序的过程中,能在O(n)时间内建好堆; 但是建好堆后,对剩余的(n-i)的每个元素在log(n-i)时间内完成排序了;
代码:
///heap_sort algorithm void HeapSort(int a[],int n){///n is the index ,not the length for(int i = n/2;i>=0;i--){///build a big root heap Shift(a,i,n); for(int p = 0;p<=n;p++){ cout<<a[p]<<" "; }cout<<endl; } for(int i = n;i>0;i--){ int temp = a[0]; a[0] = a[i]; a[i] = temp; Shift(a,0,i-1);///build the a[0..(i-1)] as a big-root heap } } void Shift(int a[],int i,int m){///m is the index ,not the length ///这个算法假设a[i+1...m]中的各个元素满足堆的定义,本算法调整a[i]使得序列a[i..m]中的元素满足堆的性质 ///要求不高,只是每次使大根堆的 元素数量多一个 ///调堆的过程,每次只在一个子树中操作,调换; ///那么什么时候调换截止呢,就是说a[i]找到了要找的位置,就行了,我们这个函数的任务就结束了. int temp = a[i];///暂存a[i]到temp if(i==1){ cout<<"start"<<endl; } for(int j = 2*i+1;j<=m;j=2*i+1){///a[i]的左右孩子的下标分别是[2i],[2i+1] if(j<m && a[j]<a[j+1]) j++;///若a[i]的右孩子存在,且关键字比较大,沿右孩子筛选 ///找当前a[i]最大的孩子节点和a[i]相比较即可, ///大根堆的定义:只有节点和孩子节点的比较,没有孩子节点之间比较的意思 if(temp<a[j]){///这个孩子的key比较大 a[i] = a[j];///将这个孩子节点放到双亲的位置 i = j;///修改当前被调整的节点 }else{ break;///调整完毕 } }///for a[i] = temp;///将最初被调整节点放到正确位置 }
梳理一边数组建堆的过程:
建堆也是不断调堆Shift的过程,shift(int a[],int i,int m)函数所作的工作就是将数组a[i...m] (都是下标)。
归并排序:
归并排序思想:
代码:
///merger_sort algorithm void mergeArray(int * arrs, int * tempArr, int left, int middle, int right){ int i = left, j = middle ; int m = middle + 1, n = right; int k = 0; while(i <= j && m <= n){ if(arrs[i] <= arrs[m]) tempArr[k++] = arrs[i++]; else tempArr[k++] = arrs[m++]; } while(i <= j) tempArr[k++] = arrs[i++]; while(m <= n) tempArr[k++] = arrs[m++]; for(i=0; i < k; i++) arrs[left + i] = tempArr[i]; } void mergeSort(int * arrs, int * tempArr, int left, int right){ if(left < right){ int middle = (left + right)/2; mergeSort(arrs, tempArr, left, middle); mergeSort(arrs, tempArr, middle + 1, right); mergeArray(arrs, tempArr, left, middle, right); } } };
相关文章推荐
- mysql 查询某个日期时间段,每天同一时间段的数据
- [置顶] 返回值类型是接口
- 怎样判断iOS App是通过哪种途径启动的?
- webview 打开 activity
- 合并两个已经排序的链表
- 数字图像处理(Matlab)读书笔记
- 检查字符串中出现aa字符串的所有位置
- 如何配置国际化资源文件
- Forrest 2015年第三季度内存数据库分析报告
- core生成在当前目录
- Java 内存
- java设计模式:适配器模式
- MySQL按照汉字的拼音排序
- Android系统启动过程详解
- 201. Bitwise AND of Numbers Range
- PHPWord利用模板替换字符串生成精确的word文档
- java 随机生成四位数验证码
- java 彩票36选6
- springMVC+mybatis 进行单元测试时 main SqlSessionFactoryBean - Parsed configuration file: 'class path resource' 无限的读取xml文件
- Runner之记计账项目的典型用户分析