归并排序和堆排序

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

归并排序和堆排序
知识点总结报告
知识点:
归并排序
(原理)归并排序是多次将两个或两个以上的有序表合并成⼀个新的有序表。

最简单的归并是直接将两个有序的⼦表合并成⼀个有序的表,即⼆路归并。

⼆路归并排序基本思路是将R[0..n-1]成是n个长度为1的有序序列,然后进⾏两两归并,得到|¯n/2¯|个长度为2(最后⼀个有序序列的长度可能为2)的有序序列,再进⾏两两归并,得到|¯n/4¯|个长度(最后⼀个有序序列的长度可能⼩于4)的有序序列,。

直到得到⼀个长度为n的有序序列。

将两个有序表直接归并为⼀个有序表的算法
void Merge(RecType R[ ],int low,int mid,int high) //归并R[low..high] //将两个有序表直接归并为⼀个有序表的算法
{ RecType *R1;
int i=low,j=mid+1,k=0; //k是R1的下标,i j分别为第1、2段的下标
R1=(RecType *)malloc((high-low+1)*sizeof(RecType)); //动态分配空间
while(i<=mid &&j<high) //在第1段和第2段均未扫描完时循环
if(R[i].key<=R[j].key) //在第1段中的元素放⼊R1中
{ R1[k]=R[i];
i++;k++;
}
else //在第2段中的元素放⼊R1中
{ R1[k]=R[j];
j++;k++;
}
while(i<=mid) //将第1段余下的部分复制到R1
{ R1[k]=R[i];
i++;k++;
}
while(j<=high) //将第2段余下的部分复制到R1
{ R1[k]=R[j];
j++;k++;
}
for(k=0,i=low;i<=high;k++,i++) //将R1复制到R[low..high]中
R[i]=R1[k];
free(R1);
}
⼀趟归并的算法
void MerPass(RecType R[ ],int length,int n) //对整个排序序列进⾏⼀趟归并
{ int i;
for(i=0;i+2*length-1<n;i=i+2*length) //归并length长的两相邻⼦表
Merge(R,i,i+length-1,i+2*length-1);
if(i+length-1<n-1) //余下两个⼦表,后者的长度⼩于length
Merge(R,i,i+length-1,n-1); //归并这两个⼦表
}
⼆路归并
⼆路归并中⾃底向上的算法
void MergeSort(RecType R[ ],int n) //⼆路归并排序
{ int length;
for(length=1;length<n;length=2*length) //进⾏|¯log2n¯|
MergePass(R,length,n);
}
⼆路归并中⾃顶向下的算法
void MergeSortDC(RecType R[ ],int low,int high) //对R[low..high]进⾏⼆路归并排序
{ int mid;
if(low<high)
{ mid=(low+high)/2;
MergeSortDC(R,low,mid);
MergeSortDC(R,mid+1,high);
Merge(R,low,mid,high);
}
}
void MergeSort1(RecType R[ ],int n) //⾃顶向下的⼆路归并算法
{ MergeSortDC(R,0,n-1);
}
堆排序
(原理)堆排序是⼀种树形选择排序⽅法。

它的特点是将R[1..n](R[i]的关键字为ki)看成⼀棵完全⼆叉树的顺序存储结构。

利⽤完全⼆叉树中双亲结点和孩⼦结点之间的位置关系在⽆序区中选择关键字最⼤(或最⼩)的元素。

(1)满⾜Ki<=K2i且Ki<=K2i+1 为⼩根堆。

就是树中分⽀任何结点的关键字都⼩于其孩⼦结点的关键字。

(2)满⾜Ki>=K2i且Ki>=K2i+1 (1<=i<=|_n/2_|)为⼤根堆。

就是树中分⽀任何结点的关键字都⼤于等于其孩⼦结点的关键字。

排序算法
堆排序的关键是筛选,过程是假如完全⼆叉树的根结点是R[i],它的左、右⼦树已是⼤根堆,将其两个孩⼦的关键字R[2i].key、
R[2i+1].key的最⼤者与R[i].key⽐较。

若R[i].key较⼩,将其与最⼤孩⼦进⾏交换,这有可能破坏下⼀级的堆。

继续采⽤上述⽅法构造下⼀级的堆,直⾄这棵完全⼆叉树变成⼀个⼤根堆为⽌。

假设对R[low..high]进⾏筛选,必须满⾜R[low]为根结点的左⼦树和右⼦树均为⼤根堆,其筛选算法sift()如下
void sift(RecType R[ ],int low,int high)
{ int i=low,j=2*i; //R[j]是R[i]的左孩⼦
RecType tmp=R[i];
while(j<=high)
{ if(j<high&&R[j].key<R[j+1].key) //若右孩⼦较⼤,把j指向右孩⼦
j++;
if(tmp.key<R[j].key) //若根结点⼩于最⼤孩⼦的关键字
{ R[i]=R[j]; //将R[i]调整到双亲结点位置上
i=j; //修改i和j值,以便继续向下筛选
j=2*i;
}
else break; //若根结点⼤于等于最⼤孩⼦关键字,筛选结束 }
R[i]=tmp; //被筛选结点放⼊最终位置上
}
实现堆排序算法
void HeapSort(RecType R[ ],int n)
{ int i;
for(i=n/2;i>=1;i--) //循环建⽴初始堆,调⽤sift算法|_n/2_|次
sift(R,i,n);
for(i=n;i>=2;i--) //进⾏n-1趟完成堆排序,每趟堆中元素个数减1
{ swap(R[1],R[i]); //将最后⼀个元素与根R[1]交换
sift(R,1,i-1); //对R[1..i-1]进⾏筛选,得到i-1个结点的堆
}
}。

相关文档
最新文档