插入排序的c++代码实现

头文件是三个插入排序的代码,mian函数是一个测试样例

在第i轮,看的是第i+1个数据(位序)要插入在前面i个数据已经排好序的序列的哪个位置

每次就是比较第j位(j=i-1;j>=0;j--)要是还是比这个小,就直接让j位的值移动到j+1位置上去,直到比下一位要大停止,并将之放在这个位置上

(从位序为2的开始第一轮)

insertsort3.h

#pragma once
//直接插入排序(无哨兵)
//这种是最常规的,数组0位置无哨兵(数组是0~length-1)。没有涉及二分查找
template<typename DataType>
void insertSort(DataType D[], int length) {
    DataType key;
    int i, j;
    for (i = 1; i < length; ++i) {//算法从第二个开始
        if (D[i] < D[i - 1]) {
            key = D[i];
            for (j = i - 1; j >= 0 && key < D[j]; --j)//因为无哨兵在查找的过程中需要每次多判断 j是否超出0
                D[j + 1] = D[j];
            D[j + 1] = key;//小心这里是+1
        }
    }
}

//直接插入排序(有哨兵)
//数组0位置有哨兵(无实际意义,方便保存以及比较,数组实际是1~length)。没有涉及二分查找
template<typename DataType>
void insertSort_s(DataType D[], int length) {
    int i, j;
    for (i = 2; i <= length; ++i) {//算法从第二个开始,但这里从[2]是因为 [0]保存的是哨兵
        if (D[i] < D[i - 1]) {
            D[0] = D[i];
            for (j = i - 1; D[0] < D[j]; --j)
                D[j + 1] = D[j];
            D[j + 1] = D[0];//小心这里是+1
        }
    }
}


//折半插入排序(有哨兵)
// 数组0位置有哨兵(无实际意义,方便保存以及比较,数组实际是1~length)。涉及二分查找
template<typename DataType>
void insertSort_s_bs(DataType D[], int length) {//bs: binary search
    int i, j, low, mid, high;
    for (i = 2; i <= length; ++i) {
        if (D[i] < D[i - 1]) {
            D[0] = D[i];
            low = 1;
            high = i - 1;//high不是length
            while(low <= high) { //此处是含有等于的
                mid = (low + high) / 2;
                if (D[0] < D[mid]) high = mid - 1;
                else low = mid + 1;//这块就是保证算法稳定性的。要是遇到相同往右边放
            }
            for (j = i - 1; j >= low; --j)  D[j + 1] = D[j];
            D[low] = D[0];
        }
    }
}//刚刚一想,此处data[0]可有可无,不算是哨兵了,只是一个单纯的临时存放变量罢了

main.cpp

// 8.1inserting_sort.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//插入排序的代码实现以及例题

#include <iostream>
#include"insertsort3.h"
using namespace std;

int main()
{
    int data[8] = { 43,35,1,87,99,67,78,10 };
    int length = 8;

    cout << "原数列:"<<endl;
    for (int i = 0; i < length; ++i)
        cout << data[i] << " ";
    cout << endl;

    insertSort(data, length);
    cout << "现数列1:(无哨兵,无二分查找)" << endl;
    for (int i = 0; i < length; ++i)
        cout << data[i] << " ";
    cout << endl;

    int data2[9] = { 0,43,35,1,87,99,67,78,10 };//还是原来的,懒得重新赋值,0是哨兵
    length = 8;//实际的数组长度
    insertSort_s(data2, length);
    cout << "现数列2:(有哨兵,无二分查找)" << endl;
    for (int i = 0; i < length; ++i)
        cout << data2[i] << " ";
    cout << endl;

    int data3[9] = { 0,43,35,1,87,99,67,78,10 };//还是原来的,懒得重新赋值
    length = 8;//实际的数组长度
    insertSort_s_bs(data3, length);
    cout << "现数列3:(有哨兵,有二分查找)" << endl;
    for (int i = 0; i < length; ++i)
        cout << data3[i] << " ";
    cout << endl;

    return 0;
}

易错点:

1、数组的设置和长度,我的第一个数组是无哨兵的,所以数组建立data[8] 长度8,但是后面两个就要考虑到自带哨兵,data[9]长度8,其中data[0]就是用来让哨兵的位置

特别的:

1、哨兵的作用是:在无哨兵的情况下,每轮的向前比较大小的查找是需要多判断一个往前的下标j有没有数组越界,有没有小于0,在有哨兵的时候哨兵为data[i]的值,那么比较条件都可以收到data[j] > data[0]中了

2、在查找这步使用二分查找:这样可以使查找时时间复杂度从n变成:logn,但是需要注意的是:

二分查找的结束条件没有data[mid]=data[0],这步不加很有必要,因为要保证算法的稳定性,所以出现相同的时候,你要确保必须放在所有的相同的最后面(因为最开始他就在后面一些嘛,从后往前换),所以二分查找的退出条件只有 low>high。并且在low=high的情况下也不能确定因为low=mid=high的时候这个数可能比他大可能比他小,需要从右中两个位置继续抉择选择位置的。

但是最后都是low的位置为我应该把原始数据放在位置上

 

关于时间和空间复杂度:

无哨兵,no二分查找:时间复杂度:最优:o(n)就直接不用去查找以及移动了,只需要找到下一个然后和前面一个比较一下,然后就继续下一个,轮一数组就结束。

                                                           最坏+平均:o(n^2)

                                     空间复杂度:o(1) 只有一个key

有哨兵,no二分查找:时间复杂度:最优:o(n)就直接不用去查找以及移动了

                                                           最坏+平均:o(n^2) 只是比无哨兵查找每次少个条件

                                     空间复杂度:o(1) 可能就i,j

有哨兵,采用二分查找:时间复杂度:最优:o(n)就直接不用去查找以及移动了

                                                           最坏+平均:o(n^2) 虽然查找变成了logn,但是每次还是需要把从low到i-1的位置全部移动一次,和之前一样的,所以还是o(n^2)

                                     空间复杂度:o(1) 就i,j,low,mid,high

并且忘记提了,顺序表和链表的情况是都可以实现的,这里是只用了顺序表的数组来写的,而且用链表的时候,在插入的时候就不需要一个一个的移动了,虽然查找还是需要一个一个的比大小,所以时间复杂度以及类型(有无哨兵有无二分查找)都是和数组的情况一样的

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值