直接插入排序希尔排序归并排序的区别与联系
Posted sanqima
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了直接插入排序希尔排序归并排序的区别与联系相关的知识,希望对你有一定的参考价值。
直接插入排序、希尔排序,都属于插入排序,即每一趟选择一个关键字,把它插入到已排序序列的适当位置,直到整个序列都有序为止。而归并排序,比如,2路归并,是将2个子有序表,合并成一个新的有序表,这个新的有序表再跟其他字表合并,循环往复,两两归并,直到整个序列都成有序的。
对比它们的时间复杂度、空间复杂度、稳定性,如下:
算法对比 | 直接插入排序 | 希尔排序 | 归并排序 |
---|---|---|---|
平均时间复杂度 | O(n^2) | O(n^1.5) | O(nlogn) |
最坏情况 | O(n^2) | O(n^2) | O(nlogn) |
最好情况 | O(n) | O(n^1.3) | O(nlogn) |
空间复杂度 | O(1) | O(1) | O(n) |
属于稳定算法 | 属于 | 不属于 | 属于 |
1、直接插入排序
基本思路:依次将每个记录插入到一个有序的序列里。假设记录存放在R[0,n-1]之中,R[0,i-1]是已排好序的记录区(也叫有序区),R[i,n-1]是未排序的记录区(无序区)。每次将R[i]插入到R[0,i-1]之中,使得R[0,i]成为有序的,直到i=n-1为止。
//插入排序源码
//直接插入排序
void InsertSort(vector<int> &list) {
for (int i = 1; i < list.size();i++)
{
int tmp = list[i];
int j = 0;
for (j = i - 1; j >= 0 && tmp < list[j];j--)
{
list[j + 1] = list[j];
}
list[j + 1] = tmp;
}
}
2、希尔排序
希尔排序,又称"缩小增量排序"方法,它是一种改良版的插入排序。
基本思路:将记录按下标的一定增量d分组,对每组记录采用直接插入排序方法进行排序,随着增量逐渐减小,所分成的组包含的记录越来越多。当增量的值减小到1时,整个数据合成一组,变成一组有序序列。
//希尔排序的源码:
//希尔排序
void ShellSort(vector<int> &list) {
int step = list.size() / 2;
while (step >= 1)
{
for (int i = step; i < list.size();i++)
{
int tmp = list[i];
int j = 0;
for (j = i - step; j >= 0 && tmp < list[j];j = j - step)
{
list[j + step] = list[j];
}
list[j + step] = tmp;
}
step = step / 2;
}
}
3、归并排序
基本思路:将R[0,n-1]看成是n个长度为1的有序表,把相邻的有序表成对合并,得到n/2长度为2的有序表;然后,将这些长度为2的有序表,继续成对合并,得到n/4个长度为4的有序表,如此反复进行下去,最终得到一个长度为n的有序表。
如果在归并的过程中,以2位基数进行合并,则称为二路归并排序;若以n为基数进行合并,则称为n路归并排序。
//二路归并排序源码:
//------------------- 归并排序 ---------------------
//合并
void merge(vector<int> &list, vector<int> &tmplist, int left, int mid, int right){
int leftEnd = mid - 1;
int rightStart = mid;
int tmpIndex = left;
int tmpLength = right - left + 1;
while ((left <= leftEnd)&&(rightStart <= right))
{
if (list[left] < list[rightStart])
{
tmplist[tmpIndex] = list[left];
tmpIndex++;
left++;
}
else {
tmplist[tmpIndex] = list[rightStart];
tmpIndex++;
rightStart++;
}
}
//判断左子区间
while (left <= leftEnd) {
tmplist[tmpIndex] = list[left];
tmpIndex++;
left++;
}
//判断右子区间
while (rightStart <= right) {
tmplist[tmpIndex] = list[rightStart];
tmpIndex++;
rightStart++;
}
//交换数据
for (int i = 0; i < tmpLength; i++){
list[right] = tmplist[right];
right--;
}
}
//排序
void MergeSort(vector<int> &list, vector<int> &tmplist, int left, int right) {
if (left < right)
{
int mid = (left + right) / 2;
//划分左区间
MergeSort(list, tmplist, left, mid);
//划分右区间
MergeSort(list, tmplist, mid + 1, right);
//数组合并
merge(list, tmplist, left, mid + 1, right);
}
}
4、完整代码
//sort.cpp
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
//直接插入排序
void InsertSort(vector<int> &list) {
for (int i = 1; i < list.size();i++)
{
int tmp = list[i];
int j = 0;
for (j = i - 1; j >= 0 && tmp < list[j];j--)
{
list[j + 1] = list[j];
}
list[j + 1] = tmp;
}
}
//希尔排序
void ShellSort(vector<int> &list) {
int step = list.size() / 2;
while (step >= 1)
{
for (int i = step; i < list.size();i++)
{
int tmp = list[i];
int j = 0;
for (j = i - step; j >= 0 && tmp < list[j];j = j - step)
{
list[j + step] = list[j];
}
list[j + step] = tmp;
}
step = step / 2;
}
}
//------------------- 归并排序 ---------------------
//合并
void merge(vector<int> &list, vector<int> &tmplist, int left, int mid, int right){
int leftEnd = mid - 1;
int rightStart = mid;
int tmpIndex = left;
int tmpLength = right - left + 1;
while ((left <= leftEnd)&&(rightStart <= right))
{
if (list[left] < list[rightStart])
{
tmplist[tmpIndex] = list[left];
tmpIndex++;
left++;
}
else {
tmplist[tmpIndex] = list[rightStart];
tmpIndex++;
rightStart++;
}
}
//判断左子区间
while (left <= leftEnd) {
tmplist[tmpIndex] = list[left];
tmpIndex++;
left++;
}
//判断右子区间
while (rightStart <= right) {
tmplist[tmpIndex] = list[rightStart];
tmpIndex++;
rightStart++;
}
//交换数据
for (int i = 0; i < tmpLength; i++){
list[right] = tmplist[right];
right--;
}
}
//排序
void MergeSort(vector<int> &list, vector<int> &tmplist, int left, int right) {
if (left < right)
{
int mid = (left + right) / 2;
//划分左区间
MergeSort(list, tmplist, left, mid);
//划分右区间
MergeSort(list, tmplist, mid + 1, right);
//数组合并
merge(list, tmplist, left, mid + 1, right);
}
}
//输出所有的元素
void printList(vector<int> list){
for (int i = 0; i < list.size(); i++){
printf("%d ", list[i]);
if ((i + 1) % 10 == 0)
printf("\\n");
}
printf("\\n");
}
int main() {
int arry[6] = { 40,20,80,50,30,60 };
vector<int> dataVec(arry, arry + 6);
//1)直接插入排序
//InsertSort(dataVec);
//printList(dataVec);
//2)希尔排序
//ShellSort(dataVec);
//printList(dataVec);
//3)归并排序
vector<int> dataTmp;
dataTmp.resize(6);
MergeSort(dataVec, dataTmp, 0, dataVec.size() - 1);
printList(dataVec);
system("pause");
return 0;
}
5、参考文献
李春葆.数据结构习题与解析B级.2006
以上是关于直接插入排序希尔排序归并排序的区别与联系的主要内容,如果未能解决你的问题,请参考以下文章
直接插入排序 ,折半插入排序 ,简单选择排序, 希尔排序 ,冒泡排序 ,快速排序 ,堆排序 ,归并排序的图示以及代码,十分清楚
八大基础排序中(直接插入排序,希尔排序,冒泡排序, 快速排序,归并排序,简单选择排序)
C# 各种内部排序方法的实现(直接插入排序希尔排序冒泡排序快速排序直接选择排序堆排序归并排序基数排序)
C# 各种内部排序方法的实现(直接插入排序希尔排序冒泡排序快速排序直接选择排序堆排序归并排序基数排序)