虽然写这个博客主要目的是为了给我自己做一个思路记忆录,但是如果你恰好点了进来,那么先对你说一声欢迎。我并不是什么大触,只是一个菜菜的学生,如果您发现了什么错误或者您对于某些地方有更好的意见,非常欢迎您的斧正!
插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。插入排序可分为直接插入排序和二分插入排序。
直接插入排序:
我的理解:一个一维数组arr,第一位也就是arr[0]为空,我真正的数组在arr[0]到arr[n]的部分,也就是说,数组后半部分是未排序的,前面是已经排序好的,然后依次从后面插入到前面已排序好的部分,排序完成后把最后一位置为空。
为了显得一目了然,我们用图表示一下这个算法里几种典型的插入。假设初始数为
第一步,把arr[1]的13赋值给arr[0],数组变为
接下来进入循环,i=2,j=0,if语句判断出arr[2]>arr[0],于是arr[2]赋值给arr[1],数组变为
同时跳出j循环,进入下一个i循环,也就是对81后面的数进入插入。
13 | 81 | ... |
第一步,把arr[1]的13赋值给arr[0],数组变为
13 | 13 | 81 | ... |
接下来进入循环,i=2,j=0,if语句判断出arr[2]>arr[0],于是arr[2]赋值给arr[1],数组变为
13 | 81 | 81 | ... |
再假设已经插入前三位,要进行第四位的插入,假设数组为
前三位已经插入完成了,16是待插入的。此时i=4,j=2, 每次比较arr[i]都小于arr[j],循环过程中通过 arr[j+1]=arr[j]将前面的数往后移动,一直到j=0 时发现arr[j]< arr[i],此时的数组:
第二个22的位置就是16要插入的位置,此时j=0,通过 arr[j+1]=arr[i],把16插入到了正确的位置,然后跳 出j循环。那么如果要插入的是8呢,此时j=0,显然不可 能继续了,我们可以看到后面的代码中有对j=0并且数字还 没有插入的情况的判断,这个时候已经完成了前面的数字的 全体后移,我们要做的只是把那个最小的数字放到数组的第一位 ,也就是arr[0]=arr[i],这样就插入到了头部。
那么来看我的代码部分:
13 | 22 | 34 | 34 | 16 | ... |
前三位已经插入完成了,16是待插入的。此时i=4,j=2, 每次比较arr[i]都小于arr[j],循环过程中通过 arr[j+1]=arr[j]将前面的数往后移动,一直到j=0 时发现arr[j]< arr[i],此时的数组:
13 | 22 | 34 | 34 | 16 | ... |
13 | 22 | 22 | 34 | 16 | ... |
第二个22的位置就是16要插入的位置,此时j=0,通过 arr[j+1]=arr[i],把16插入到了正确的位置,然后跳 出j循环。那么如果要插入的是8呢,此时j=0,显然不可 能继续了,我们可以看到后面的代码中有对j=0并且数字还 没有插入的情况的判断,这个时候已经完成了前面的数字的 全体后移,我们要做的只是把那个最小的数字放到数组的第一位 ,也就是arr[0]=arr[i],这样就插入到了头部。
直接插入排序.h
#pragma once
typedef int dataType;
/*打印数组*/
void PrintArray(dataType arr[], int length);
/*数组初始化*/
void InitArray(dataType arr[], int length);
/*直接插入排序*/
void DirectInsertSort(dataType arr[], int length);
/*直接插入排序的测试函数*/
void TestDirectInsrtSort();
直接插入排序.cpp
#include "直接插入排序.h"
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
/*打印数组*/
void PrintArray(dataType arr[], int length)
{
for (int i = 0; i < length; i++)
{
if (arr[i] > 0)
cout << arr[i] << " ";
}
cout << endl;
}
/*数组初始化*/
void InitArray(dataType arr[], int length)
{
srand((unsigned)time(NULL));/*设置随机数种子*/
arr[0] = -1;/*第一位要留出来用来插入*/
for (int i = 1; i < length; i++)
{
arr[i] = rand() % 91 + 10;/*rand()%(Y-X+1)+X,生成X-Y之间的数*/
}
}
/*直接插入排序*/
void DirectInsertSort(dataType arr[], int length)
{
arr[0] = arr[1];/*先把数组第一个数组插入到第一位*/
for (int i = 2; i < length; i++)
{
for (int j = i - 2; j >= 0; j--)
{
/*如果未排序的数比已经排序好的最后一个数要大,就插入到末尾,同时对下一个进行判断*/
if (arr[i] >= arr[j])
{
arr[j + 1] = arr[i];
break;
}
/*否则就将前面的数一个个后移*/
else
{
arr[j + 1] = arr[j];
if (0 == j)
arr[0] = arr[i];
}
}
}
/*排序完成后最后一位置空*/
arr[length - 1] = -1;
}
/*直接插入排序的测试函数*/
void TestDirectInsrtSort()
{
int length;
cout << "输入你理想的数组长度:";
cin >> length;
length++;/*我们的需要的数组得多一位*/
dataType *arr = new dataType[length+1];/*创建一个一维数组*/
InitArray(arr, length);/*初始化数组*/
PrintArray(arr, length);/*打印这个数组*/
DirectInsertSort(arr, length);/*对这个数组进行直接插入排序*/
PrintArray(arr, length);/*再次打印这个数组*/
delete[] arr;/*销毁这个数组*/
}
最后在主函数中调用测试函数TestDirectInsrtSort()就可以了。
int main()
{
TestDirectInsrtSort();
getchar();
getchar();
return 0;
}
二分排序:
(插入一句废话哈:每次看到二分什么的,都莫名觉得很高大上,感觉就是一个大佬算法,好了,那么就直接看我对这个二分排序的理解吧。)二分排序,我后来觉得与直接插入其实也差不多,插入还是同样的插入,只是寻找插入位置,从一个个寻找,变成了一半一半地寻找那个要插入的位置。就是不断通过while循环中变换left与right的值. 假设我有一个数组:7,11,18,21,30,35,43,45,45,19,...
arr[0]~arr[7]是已经插入完成的,arr[9]是即将要插入的。
while的作用是寻找要插入的位置,寻找的结果是将right赋值为要插入位置的前一位
| left=0,mid=3,right=6
| ∵arr[mid](21)>arr[i](19) right=mid-1=2
| 接下来看7,11,18
| left=0,mid=1,right=2
| arr[mid](11) < arr[i](19),left=mid+1=2
| left=2,mid=2,right=2
| 此时只剩下18
| arr[mid](18)< arr[i](19),left=mid+1=3>right(2),循环结束
此时right=2,恰好是要插入位置的前一位
那么来看我的代码部分:
二分排序.h
#pragma once
typedef int dataType;
/*打印数组*/
void PrintTwoSortArray(dataType arr[], int length);
/*数组初始化*/
void InitTwoSortArray(dataType arr[], int length);
/*二分排序*/
void TwoSort(dataType arr[], int length);
/*二分排序的测试函数*/
void TestTwoSort();
二分排序.cpp
#include "二分排序.h"
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
/*打印数组*/
void PrintTwoSortArray(dataType arr[], int length)
{
for (int i = 0; i < length; i++)
{
if (arr[i] > 0)
cout << arr[i] << " ";
}
cout << endl;
}
/*数组初始化*/
void InitTwoSortArray(dataType arr[], int length)
{
srand((unsigned)time(NULL));/*设置随机数种子*/
arr[0] = -1;/*第一位要留出来用来插入*/
for (int i = 1; i < length; i++)
{
arr[i] = rand() % 91 + 10;/*rand()%(Y-X+1)+X,生成X-Y之间的数*/
}
}
/*二分排序*/
void TwoSort(dataType arr[], int length)
{
/*一开始我们还是先把第一个数字插入到数组头部*/
arr[0] = arr[1];
/*接下来才开始二分插入,从arr[2]开始插入,所以i=2*/
for (int i = 2; i < length; i++)
{
int left = 0;
int right = i - 2;/*arr[i-2]才是已经排序好的数组的最后一位*/
while (left <= right)
{
int mid = (left + right) >> 1;/*相当于(left + right)÷2*/
/*调整要折半的数组范围,根据left与right的值来变化*/
if (arr[mid] > arr[i])
{
right = mid - 1;
}
else
{
left = mid + 1;
}
}
for (int j = i-2; j > right; j--)
{
arr[j + 1] = arr[j];
}
arr[right + 1] = arr[i];
}
arr[length - 1] = -1;/*最后一位置空*/
}
/*二分排序的测试函数*/
void TestTwoSort()
{
int length;
cout << "输入你想要的数组长度:";
cin >> length;
length++;/*我们的需要的数组得多一位*/
dataType *arr = new dataType[length + 1];/*创建一个一维数组*/
InitTwoSortArray(arr, length);/*初始化数组*/
PrintTwoSortArray(arr, length);/*打印这个数组*/
TwoSort(arr, length);/*对这个数组进行直接插入排序*/
PrintTwoSortArray(arr, length);/*再次打印这个数组*/
delete[] arr;/*销毁这个数组*/
}
主函数
#include "二分排序.h"
#include <stdio.h>
int main()
{
TestTwoSort();
getchar();
getchar();
return 0;
}
参考网站以及博客:
百度百科https://baike.baidu.com/item/%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F/7214992
https://baike.baidu.com/item/%E4%BA%8C%E5%88%86%E6%8E%92%E5%BA%8F/15421651?fr=aladdin#1_1
算法排序----二分排序法
https://blog.csdn.net/qq1641530151/article/details/80631201