C语言数据结构——插入排序InsertSort
一、你需要明白的概念:
1. 什么是插入排序捏?
插入排序的概念大家在网上随便一搜就可以搜到清楚的定义,简单来说就是:对一组关键字或者数组元素进行排序,把数组中的每一个元素与当前已经排好顺序的序列中的元素进行比较,然后找到正确的元素,然后插入,形成新的有序序列。
2. 给你举一个插入排序的例子:
比如有一个无序序列如下: 4, 7,5, 8, 9, 1, 0. 在数组中的情况如图片:
现在对这个数组进行插入排序。
1. 首先默认首元素(即下标为0的元素:4)是有序序列,我们从第二个元素开始比。为了方便说明,后面所说的x号元素指的就是下标为x的第x+1个元素。如下图,0号元素已经属于有序序列:
2. 1号元素为7,与有序序列最近的元素相比,即4:7>4,则不需要排序,归入有序序列,如下图:
3. 2号元素为5,与有序序列的最近元素相比,即7:5<7,需要排序。接下来用5依次从右到左和有序序列的元素相比。7已经比较过了,接下来向左比较4,5>4,说明找到正确位置:5在4后面插入。如此归入并形成新的有序序列:
4. 3号元素为8,与有序序列最近元素相比,即8>7,无需排序,直接归入有序序列,如下图:
5. 4号元素也是上面的情况:
6. 5号元素为1,和有序序列元素开始比较,比较顺序如图:
经过比较,5号元素1为首元素,后面的0号元素也是一样,最后排序结果如图:
二、模块分析
根据上面的例子,我们可以大致探知我们未来的代码应该大体有哪些要素:
1. 外循环:
用来从数组左端到右端依次进行和有序序列比较,我们可以用for循环, 用来从头到尾遍历,用变量index来控制。由于0号元素默认为有序,则index初始值为1。该部分伪代码如下:
for(int index=1;index<array.length;index++)
{
if(array[index]>array[有序序列最近元素])
{
array[index]归入有序序列;
}
else
{
在有序序列中寻找正确位置插入;
}
}
2. 内循环:
当需要插入到正确位置的时候,又要对有序序列的那一部分进行遍历比较,寻找正确位置进行插入。
我们知道,一个元素正确的位置条件为:前驱<元素<后继。那么我们就要负责在内循环中寻找有序序列中小于这个数字的第一个数字,然后插入其后。我们用变量locate循环,初始值为当前有序序列最近位置。
在插入过程中是难点,如果前驱>元素,说明不是正确位置,那么变量locate还要继续向左移动,即locate-=1;然后元素后移,为插入元素挪位置。这样就不用把所有元素后移,每次只移动1个元素就好,接下来我们举例子加上图片说明:
举例:4,6,8,5,9。如下图:
由前文得知,index=1,前驱 locate=0。array[index] > array[locate],则归入有序序列,即:index+=1;如下图:
此时index=2,locate=1。array[index] > array[locate], 则归入有序序列,即:index+=1;如下图:
此时index=3,locate=2。array[index] < array[locate], 则将array[locate] 直接赋值给后面的元素空间,实现后移,即将8赋值给5,但是为了防止5被覆盖,我们先用一个临时变量temp存起来,temp=5.既然这个locate不正确,我们就继续前移,继续比较。如下图:图1为后移前,图2为后移后:
此时index=3,locate=1,array[index]此时不可以和array[locate]继续比较了,因为此时array[locate]的值已经从5变成了8,所以我们要和 temp比较哦,因此我们可以实现就用temp存起来,前面也用temp比较哦。
此时 array[locate]=6>5,依旧不正确,继续将array[locate]赋值给后面一个元素array[locate+1],即6赋值给2号元素8,同时locate还要继续前移比较,如下图:
此时locate=0,index=3. array[locate]=4<5, 位置正确,我们要将5插入locate之后,直接赋值就可以,如下图:
退出循环,即break,此时 index 没有被改变,继续进行外循环,对下一个位置的元素进行内循环比较插入。
while(locate>=0)
{
if(array[locate]>目标元素)//未找到正确元素位置
{
array[locate+1]=array[locate]//元素后移,为目标元素前面挪位
locate-=1;
}
else //也就是说找到了正确位置
{
array[locate+1]=目标元素值;
break;
}
}
三、C++代码实现:
请仔细阅读代码,便于理解,注释比较详细,其中有一些注释是前文没有的,需要好好理解
#include<iostream>
#include<iomanip>
using namespace std;
class Array {
private:
int* array;// 数组首地址,尚未申请空间
int length;//存储该数组内元素数目,即数组长度
public:
Array(int l);//含有默认参数的构造函数的声明,作用是每次定义一个这个类的变量
//就可以自动调用,不用用户专门调用,具体作用见函数定义部分
void Build();//创建这个数组的成员函数,需要用户调用
void InsertSort();//实现插入排序的成员函数,需要用户调用
void Display();//输出数组的成员函数,需要用户调用
};
/*接下来是该类的函数定义部分:*/
void Array::Display()
{
cout << "Display>> Result below:" << endl;
for (int count = 0; count < length; count++)
{
cout << array[count] << " ";
}
}
void Array::InsertSort()
{
int temp=0;//用来暂存array[index]值的变量
int index, locate;
index = 1;
for (index; index < length; index++)//外循环
{
temp = array[index];//存变量
cout << endl << "--------------------" << endl << "InsertSort>> searching data " << array[index] << endl;
locate = index - 1;//得到前驱位置
if (array[index] > array[locate])//这个条件下,即位置不正确
{
cout << "InsertSort>> " << array[index] << " > " << array[locate];
cout << " , Index moves right" << endl;//这个括号内语句是无用的,仅仅是提示作用,可以注释掉
}
else
{
while (locate >= 0)//从有序序列最近位置开始倒着遍历,直到首元素
{
if (array[locate] >= temp)//如果依旧位置不正确
{
cout << "InsertSort>> " << array[locate] << " > " << temp << " locate move left" << endl;
array[locate + 1] = array[locate];
locate -= 1;
/*赋值到后面元素,实现后移,同时locate向左移动一个元素进行下一次比较*/
}
else//位置正确
{
cout << locate + 1 << " is right location" << endl;
array[locate + 1] = temp;
break;
/*直接把temp,即目标元素赋值给locate后的元素,即插入到正确位置*/
//然后彻底跳出while循环,进行下一个元素的操作
}
}
if (locate == -1)
{
array[0] = temp;
}
/*这一部分的代码可能很少人理解,我们详细解释一下:
比如对待这一类例子:4,6,8,5,1.前面虽然容易排序为:4,5,6,8,1.到那时当
到了对1进行插入时候,哪怕到了0号元素也不是正确位置,此时我们只实现了4的向后赋值,
即:4,4,5,6,8. 此时 1 就可以直接覆盖0号元素就好了,就是这部分代码的内容。
最后一次locate=0的时候进行 1和 4的比较,结果位置依旧不正确,因此还会实行依次locate-=1
这时,locate=-1,因此可以进行这种操作:如果locate=-1,说明当前元素应该成为首元素
*/
}
}
cout << "InsertSort>> Sorting finished!" << endl;
}
void Array::Build()
{
cout << "System>> Input the " << length << " data one by one" << endl;
for (int count = 0; count < length; count++)
{
cout << count + 1 << " data: ";
cin >> array[count];
}
}
Array::Array(int l) :length(l)
{
cout << "Constructor transfered, allocate " << length << " memory space" << endl;
array = (int*)malloc(length * sizeof(int));
if (!array)
{
cout << "Warning>> Array allocate memory space failed!" << endl;
perror("Error Details: ");
cout << endl;
}
}
int main()
{
int length;
cout << "System>> Input the length of this array:";
cin >> length;
Array a(length);
a.Build();
a.InsertSort();
a.Display();
return 0;
}
四、C语言实现
尽管C++变成C语言很容易,但是为了防止有些初学者阅读,我就大体再写出来,注释依旧
#include<stdio.h>
#include<stdlib.h>
int *array;
int length;
/*接下来是该类的函数定义部分:*/
void Display()
{
printf("Display>> Result below:\n");
for (int count = 0; count < length; count++)
{
printf("%d ",array[count]);
}
}
void InsertSort()
{
int temp=0;//用来暂存array[index]值的变量
int index, locate;
index = 1;
for (index; index < length; index++)//外循环
{
temp = array[index];//存变量
printf("\n--------------------\n");
printf("InsertSort>> searching data :%d\n",array[index]);
locate = index - 1;//得到前驱位置
if (array[index] > array[locate])//这个条件下,即位置不正确
{
printf("InsertSort>> %d > %d , Index moves right\n",array[index],array[locate]);
//这个括号内语句是无用的,仅仅是提示作用,可以注释掉
}
else
{
while (locate >= 0)//从有序序列最近位置开始倒着遍历,直到首元素
{
if (array[locate] >= temp)//如果依旧位置不正确
{
printf("InsertSort>> %d > %d, locate move left\n",temp);
array[locate + 1] = array[locate];
locate -= 1;
/*赋值到后面元素,实现后移,同时locate向左移动一个元素进行下一次比较*/
}
else//位置正确
{
printf("%d is right location\n",locate+1);
array[locate + 1] = temp;
break;
/*直接把temp,即目标元素赋值给locate后的元素,即插入到正确位置*/
//然后彻底跳出while循环,进行下一个元素的操作
}
}
if (locate == -1)
{
array[0] = temp;
}
/*这一部分的代码可能很少人理解,我们详细解释一下:
比如对待这一类例子:4,6,8,5,1.前面虽然容易排序为:4,5,6,8,1.到那时当
到了对1进行插入时候,哪怕到了0号元素也不是正确位置,此时我们只实现了4的向后赋值,
即:4,4,5,6,8. 此时 1 就可以直接覆盖0号元素就好了,就是这部分代码的内容。
最后一次locate=0的时候进行 1和 4的比较,结果位置依旧不正确,因此还会实行依次locate-=1
这时,locate=-1,因此可以进行这种操作:如果locate=-1,说明当前元素应该成为首元素
*/
}
}
printf("InsertSort>> Sorting finished!\n");
}
void Build()
{
printf("System>> Input the %d data one by one", length);
for (int count = 0; count < length; count++)
{
printf("%d data:",count+1);
scanf("%d",&array[count]);
}
}
void Array(int l)
{
length=l;
printf("Constructor transfered, allocate %d memory space\n",length);
array = (int*)malloc(length * sizeof(int));
if (!array)
{
printf("Warning>> Array allocate memory space failed!\n");
perror("Error Details: ");
printf("\n");
}
}
int main()
{
int len;
printf("System>> Input the length of this array:");
scanf("%d",&len);
Array(length);
Build();
InsertSort();
Display();
return 0;
}