数据结构面试之十一——排序2(归并、快速、堆排序)
2012-09-05 00:03
369 查看
题注:《面试宝典》有相关习题,但思路相对不清晰,排版有错误,作者对此参考相关书籍和自己观点进行了重写,供大家参考。
十、数据结构面试之十一——排序2(归并、快速、堆排序)
5. 归并排序
【算法思想】:采用分治法的算法思想,将原始数组分为A、B两个子数组,然后对A、B两个子数组继续划分为A1L,A1R,B1L,B1R四个子数组,继续划分直到数组中元素个数为1个时,即认为数组有序;然后再合并相邻的数组据可以。
核心分为3步骤:
第一,Divided,对应Divided()函数。
第二,Conquer,做相关处理。
第三,Merge,对应MergeArray()函数。
步骤示意图:
【算法实现】:
6. 快速排序
【算法思想】:采用分治法的算法思想,1)初始选定枢轴元素并记录枢轴元素和left,先从后向前遍历,小于枢轴的值就和left位置元素交换;然后从前向后遍历,大于枢轴的元素则与right位置元素交换,直到left>=right结束遍历。2)一次遍历后,就能保证枢轴左侧的元素小于枢轴值,枢轴右侧的元素大于枢轴值。记录下交换后枢轴所在的位置pivotPos。3)对pivotPos左侧的元素及pivot右侧的元素依次递归调用1)、2)即可。直至全部有序后结束。
核心分为3步骤:
第一,Divided,对应Divided()函数。
第二,Conquer,做相关处理。
第三,Merge,每次Divide()后都能保证部分元素基本有序(大、小各在一侧)。
【算法实现】:
7.堆排序
【算法引出】:是简单选择排序算法的改进算法,简单选择排序中每一趟比较选出一个最小值,但是后一趟的比较中会重复前面的比较结果,存在重复。堆排序对其的改进体现在—— 每次选择最小值的同时,根据结果对其他的值进行调整。
【堆的概念】:堆是具有以下性质的完全二叉树,每个节点都大于或等于左右孩子节点的值,称为大顶堆;每个节点都小于等于左右孩子节点的值,称为小顶堆。
【算法思想】:以小顶端堆为例,(1)首先构造一个小顶堆,即堆顶为所有元素的最小值;(2)其次,将该堆顶元素与堆末尾元素互换,此时堆末尾便存储了最小元素;(3)除去堆末尾元素,对于剩余的N-i个元素反复执行(1)、(2)操作即可完成排序。
【算法实现】:
//构建与调整小顶堆.
//大顶堆的调整方法同小顶堆,所做的改变只是比较符号的变换;
//arr[j+1] > arr[j],arr[j] <= temp
十、数据结构面试之十一——排序2(归并、快速、堆排序)
5. 归并排序
【算法思想】:采用分治法的算法思想,将原始数组分为A、B两个子数组,然后对A、B两个子数组继续划分为A1L,A1R,B1L,B1R四个子数组,继续划分直到数组中元素个数为1个时,即认为数组有序;然后再合并相邻的数组据可以。
核心分为3步骤:
第一,Divided,对应Divided()函数。
第二,Conquer,做相关处理。
第三,Merge,对应MergeArray()函数。
步骤示意图:
数组下标 | a[0] | a[1] | a[2] | a[3] | a[4] | a[5] | a[6] | a[7] | a[8] | a[9] | |
元素值 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
Divided | 1 | first | | | | mid | | | | | last |
2 | first | | mid | | last | | | | | | |
3 | first | mid | last | | | | | | | | |
4 | first&mid | last | | | | | | | | | |
| |||||||||||
Merge | 5 | first&mid | last | | | | | | | | |
6 | first | mid | last | | | | | | | | |
| |||||||||||
Divided | 7 | | | | first&mid | last | | | | | |
Merge | 8 | | | | first&mid | last | | | | | |
Merge | 9 | first | | mid | | last | | | | | |
| |||||||||||
Divided | 11 | | | | | | first | | mid | | last |
12 | | | | | | first | mid | last | | | |
13 | | | | | | first&mid | last | | | | |
| |||||||||||
Merge | 14 | | | | | | first&mid | last | | | |
15 | | | | | | first | mid | last | | | |
| |||||||||||
Divided | 16 | | | | | | | | | first&mid | last |
Merge | 17 | | | | | | | | | first&mid | last |
Merge | 18 | | | | | | first | | mid | | last |
| |||||||||||
Merge | 19 | first | | | | mid | | | | | last |
【算法实现】:
template <typename T> void MergeSort(T a[], int N) { int*pTmpArray = new int ; //临时存储空间.转存用! if(pTmpArray== NULL) { cout<< "Allocate Error!" << endl; } intfirst = 0; intlast = N-1; Dirvied(a,first,last,pTmpArray); delete[]pTmpArray; } //合并数组 template <typename T> void MergeArray(T a[], int first, int mid, int last, int tempArr[]) { inti = first; intj = mid+1; intm = mid; intn = last; intk = 0; //两数组都非空 while(i<= m && j <= n) { if(a[i]< a[j]) { tempArr[k++]= a[i++]; } else { tempArr[k++]= a[j++]; } } //以下两循环代表有一个数组已空。 while(i<= m) { tempArr[k++]= a[i++]; } while(j<= n) { tempArr[k++]= a[j++]; } //临时存储的元素转存到a数组中. for(i = 0; i < k; i++) { a[first+i]= tempArr[i]; //注意此处的起点. } } //分解[递归函数] template <typename T> void Dirvied(T a[], int first, int last,int tempArr[]) { intmid; if(first< last) { mid= (first + last)/2; Dirvied(a,first,mid,tempArr);//左半部分. Dirvied(a,mid+1,last,tempArr);//右半部分. MergeArray(a,first,mid,last,tempArr); } }
6. 快速排序
【算法思想】:采用分治法的算法思想,1)初始选定枢轴元素并记录枢轴元素和left,先从后向前遍历,小于枢轴的值就和left位置元素交换;然后从前向后遍历,大于枢轴的元素则与right位置元素交换,直到left>=right结束遍历。2)一次遍历后,就能保证枢轴左侧的元素小于枢轴值,枢轴右侧的元素大于枢轴值。记录下交换后枢轴所在的位置pivotPos。3)对pivotPos左侧的元素及pivot右侧的元素依次递归调用1)、2)即可。直至全部有序后结束。
核心分为3步骤:
第一,Divided,对应Divided()函数。
第二,Conquer,做相关处理。
第三,Merge,每次Divide()后都能保证部分元素基本有序(大、小各在一侧)。
枢轴 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 72 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 48 | 85 |
pivot=72 | <--48 | | | <--42 | | left=right | | | 88--> | |
| <--48 | 6 | 57 | <--42 | 60 | 72 | 83 | 73 | 88--> | 85 |
| | | | | | | | | | |
pivot=48 | 48 | 6 | 57 | 42 | 60 | | | | | |
| <--42 | | left=right | 57--> | 60 | | | | | |
| <--42 | 6 | 48 | 57--> | 60 | | | | | |
| | | | | | | | | | |
pivot=42 | 42 | 6 | | | | | | | | |
| <--6 | 42 | | | | | | | | |
| | | | | | | | | | |
pivot=57 | | | | 57 | 60 | | | | | |
| | | | 57 | 60 | | | | | |
| | | | | | | | | | |
pivot=83 | | | | | | | 83 | 73 | 88--> | 85 |
| | | | | | | 73 | 83 | 88--> | 85 |
| | | | | | | | | | |
pivot=73 | | | | | | | 73 | 83 | | |
| | | | | | | 73 | 83 | | |
| | | | | | | | | | |
pivot=88 | | | | | | | | | 88 | 85 |
| | | | | | | | | 85 | 88 |
排序结果 | 6 | 42 | 48 | 57 | 60 | 72 | 73 | 83 | 85 | 88 |
【算法实现】:
//取枢轴,并按枢轴划分[左侧小于枢轴元素,右侧大于枢轴元素] template <typename T> int Partition(T a[], int left, int right) { swap(a[left],a[(left+right)/2]);//交换,取中间元素为枢轴元素. T pivot = a[left]; //暂存枢轴元素,用于比较 while(left< right) { while(left< right && a[right] >= pivot) { --right; } a[left]= a[right]; //[左]存储比枢轴元素小的值; while(left< right && a[left] <= pivot) { ++left; } a[right]= a[left]; //[右]存储比枢轴元素大的值; } a[left]= pivot; //存放枢轴的新位置 return left; } //递归函数 template <typename T> void QuickCurve(T a[], int left, intright) { intpivotPos = 0; if(left < right) { pivotPos= Partition (a,left,right); //获取枢轴分割后的位置,用以划分左右。 QuickCurve(a,left,pivotPos-1); //右边界-1 QuickCurve(a,pivotPos+1,right);//左边界+1 } } //快排 template <typename T> void QuickSort(T a[], int N) { QuickCurve(a,0,N-1);//left=0, right=N-1 }
7.堆排序
【算法引出】:是简单选择排序算法的改进算法,简单选择排序中每一趟比较选出一个最小值,但是后一趟的比较中会重复前面的比较结果,存在重复。堆排序对其的改进体现在—— 每次选择最小值的同时,根据结果对其他的值进行调整。
【堆的概念】:堆是具有以下性质的完全二叉树,每个节点都大于或等于左右孩子节点的值,称为大顶堆;每个节点都小于等于左右孩子节点的值,称为小顶堆。
【算法思想】:以小顶端堆为例,(1)首先构造一个小顶堆,即堆顶为所有元素的最小值;(2)其次,将该堆顶元素与堆末尾元素互换,此时堆末尾便存储了最小元素;(3)除去堆末尾元素,对于剩余的N-i个元素反复执行(1)、(2)操作即可完成排序。
【算法实现】:
//构建与调整小顶堆.
//大顶堆的调整方法同小顶堆,所做的改变只是比较符号的变换;
//arr[j+1] > arr[j],arr[j] <= temp
template<typename T> void heapAdjust(T arr[], int i, int N) { intj; inttemp = arr[i]; //临时存储需要节点信息. j= i*2+1; //左孩子节点 while(j< N) { if(j+1< N && arr[j+1] < arr[j]) { j++; //取左右孩子中的小值. } if(arr[j]>= temp) { break; //小顶堆,如果出现孩子节点值大,则终止循环. } //找寻是否存在孩子节点的孩子节点. arr[i]= arr[j]; i= j; j= 2*i + 1; }//endwhile arr[i]= temp; //存储新的位置. } //堆排序. template<typename T> void heapSort(T arr[], int N) { //构建小顶堆,初始是凌乱的,调整后成一个小顶堆 for(int i = N-1; i >= 0; i--) { heapAdjust(arr,i/2,N-1);//比较的位置从中间开始. } for(int i = N-1; i >= 0; i--) { swap(arr[i],arr[0]); heapAdjust(arr,0,i); //终止的大小为i,每次只调整根节点即可。 } }
相关文章推荐
- c++实现数据结构中的各种排序方法:直接插入、选择,归并、冒泡、快速、堆排序、shell排序
- java---插入排序,冒泡,归并,快速,希尔,堆排序
- 【程序员笔试面试必会——排序①】Python实现 冒泡排序、选择排序、插入排序、归并排序、快速排序、堆排序、希尔排序
- 数据结构-排序算法详解(插入排序,希尔排序,堆排序,归并排序,快速排序,桶式排序)
- C++数据结构 排序 二分 插入 冒泡 基数 归并 直选 快排 希尔 堆排序
- 数据结构与算法总结——排序(二)归并排序,快速排序 和 堆排序
- 快速排序、堆排序、归并排序
- 【数据结构】常用比较排序算法(包括:选择排序,堆排序,冒泡排序,选择排序,快速排序,归并排序)
- 面试常考察的排序(快速排序,归并排序,堆排序)
- C语言基本数据结构之五(折半插入,堆排序,冒泡排序,快速排序,并归排序)
- 插入 希尔 排序 堆排序 冒泡 快速 归并
- 数据结构_内部排序_希尔排序_快速排序_堆排序_归并排序_地址排序
- 微软等数据结构+算法面试100题(12)--快速排序
- 数据结构试验-快速排序-堆排序
- 笔试面试最常涉及到的12种排序算法(包括插入排序、二分插入排序、希尔排序、选择排序、冒泡排序、鸡尾酒排序、快速排序、堆排序、归并排序、桶排序、计数排序和基数排序)进行了详解。每一种算法都有基本介绍、算
- 数据结构之排序算法二:堆排序,快速排序,归并排序
- 【数据结构】排序算法:希尔、归并、快速、堆排序
- 数据结构(C#)--冒泡、插入、快速、堆、归并、希尔、选择各种排序排序过程比较以及各种排序的所用时间的对比
- 排序系列之——快速排序、堆排序、归并排序
- 数据结构各种排序法及核心思想(冒泡、鸡尾酒、选择、插入、二分法、希尔、堆、归并、快速)