数据结构面试之十一——排序2(归并、快速、堆排序)

来源:互联网 发布:淘宝无限流量手机骗局 编辑:程序博客网 时间:2024/05/16 15:03

题注:《面试宝典》有相关习题,但思路相对不清晰,排版有错误,作者对此参考相关书籍和自己观点进行了重写,供大家参考。

十、数据结构面试之十一——排序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[N]; //临时存储空间.转存用!       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,每次只调整根节点即可。       }}



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 门里面被锁了怎么办 被锁在门里怎么办 门锁住了没钥匙怎么办 车被别人锁住了怎么办 汽车轱辘被锁了怎么办 小车轮胎被锁了怎么办 国防光缆无明显标识被挖断怎么办 临工210挖掘机柴油进气怎么办 汽车抛光蜡干了怎么办 洗碗铁丝球吃了怎么办 牙套铁丝吃肚子怎么办 小铁丝吃到肚子怎么办 绿色抛光膏干了怎么办 不锈钢被盐酸弄黑了怎么办 不锈钢被草酸洗了怎么办 不锈钢洗菜盆被草酸腐蚀了怎么办 汽油发电机加了柴油怎么办 装载机发动机加入齿轮油怎么办 印尼的FromE错了怎么办 寄快递被弄坏了怎么办 福田口岸手表被扣怎么办? 网页显示与服务器连接失败怎么办 唯品会中发货无法清关怎么办 国际快递被海关扣了怎么办 我想开一家物流公司手续怎么办? 物流公司把我的货弄丢了怎么办 物流公司压司机工资怎么办 立元增压泵不出水怎么办 高浊度pac不沉怎么办 集水池中沉积大量污泥怎么办 电脑qq截图不好使怎么办 捡了个手机需要指纹怎么办 手机锁屏锁住了怎么办 三星屏锁忘记了怎么办 文字下面有蓝色直线怎么办 苹果x不能截屏了怎么办 u盘在电脑上打不开怎么办 电脑桌面上文档剪切了怎么办 苹果官网查不到保修日期怎么办 吃了发霉的花生怎么办 鸡吃大蒜多了怎么办