算法—插入排序

大致看一看

理解

相信各位看了这个图,虽然从感官上了解了它的机制,但是要将其搞成程序代码,我们还需要更细致的去分析这个问题。
在此之前,刘老大已经分析过一波了,各位可以去看下:http://liuwangshu.cn/algorithm/2-insert-hill.html,写的很不错。
但我要强调的是,这个插入排序,每次比较都是相邻俩个元素进行比较,我比较倾向于a[n+1]与a[n]进行对比为主要逻辑,并且,在比较过程中若是满足了位置对换的条件,还需要对之前比较过的数进行再次比较,直到结束,具体的说,比如这么一个数组:

int a[] = {500,86,4,9};

排序逻辑用大白话说就是:

  • a[1]与a[0]对比
    86对比500,结果是86小,由于86是a[1],500是a[0],值小的需要左移(升序),于是二者交换位置,此时数组情况是:{86,500,4,9};
  • a[2]与a[1]对比,若位置需要发生变化,则继续a[1]与a[0]对比
    1.4对比500,结果是4小,4和500位置对换,当前数组情况:{86,4,500,9};
    2.由于位置发生了变化,接着用4和86进行对比,4小,二者位置对换,当前数组情况:{4,86,500,9};
  • a[3]与a[2]对比,若位置需要发生变化,则继续a[2]与a[1]对比,若位置需要发生变化,则继续a[1]与a[0]对比
    1.9对比500,结果是9小,由于升序,所以对换二者位置,当前数组情况:{4,86,9,500}
    2.由于位置发生了变化,接着用9和86进行对比,9<86,对换二者位置,当前数组情况:{4,9,86,500}
    3.由于位置发生了变化,接着用9和4进行对比,由于9>4,不用继续进行对比。
  • 得出排序后的数组情况:{4,9,86,500}

那么根据这个逻辑我们该如何来写代码呢?

  • 首先定义一个数组int a[] = {500,86,4,9};, 然后一个for循环起手,遍历数组,这个不用想。
  • 接着,我们想好我们的对比逻辑。
//插入排序
int * insertionSort(int * a) {

	......
	for (int i = 0; i < length; i--){

		if (a[i + 1] < a[i]) {
			int temp = a[i];
			a[i] = a[i + 1];
			a[i + 1] = temp;

			//在比较过程中若是满足了位置对换的条件,还需要对之前比较过的数进行再次比较,直到结束

		}

	}

	return a;
}

代码写到这一步,本文算法的难点也就来了,我们该如何用代码来实现**“在比较过程中若是满足了位置对换的条件,还需要对之前比较过的数进行再次比较,直到结束”**,这是一个关键点。

  • 既然我们考虑到了在位置产生变化时候需要"对之前比较过的数进行再次比较",那么我们就需要定义一个变量来表示历史对比的数据索引,这里我定义了个变量—historyIndex。并且,根据我们之前分析的对比方式,从数组中顺序靠后的元素和它前一个元素进行对比,判断二者大小,看是否满足位置置换条件。结合这一波分析,我们写出了如下代码:
	fori ... {
             historyIndex = i;
	     if (a[i + 1] < a[i]) {
			....
			//在比较过程中若是满足了位置对换的条件,还需要对之前比较过的数进行再次比较,直到结束
			while (historyIndex > 0 && a[historyIndex] < a[historyIndex - 1]) {
				int temp = a[historyIndex];
				a[historyIndex] = a[historyIndex - 1];
				a[historyIndex - 1] = temp;
				historyIndex--;
			}
	     }
    }

至此,主要逻辑分析完毕,但只是主干的逻辑,一些优化比如判空,判数组边界越界这种逻辑还没说,我也不打算说了,下面我贴出优化后的完整代码(由于本人C++水平有限,所以,有的代码显得略显笨拙,大佬轻喷)。

完整代码


#include <iostream>
#include <string>
using namespace std;

int * insertionSort(int*a,int len);
void printArray(int[], string,int len);

//c++获取数组长度就是麻烦啊
template<class T>
int length(T& arr)
{
	//cout << sizeof(arr[0]) << endl;
	//cout << sizeof(arr) << endl;
	return sizeof(arr) / sizeof(arr[0]);
}

int main() {

	int  a[] = { 500,86,1,77,55,24};
	int len = length(a);
	printArray(a,"排序前", len);
	int *result = insertionSort(a, len);
	printArray(result, "排序后", len);

	system("pause");

}

//打印数组
void printArray(int *a,string tagStr,int len) {
	
	cout << tagStr << endl;
	for (int i = 0; i < len; i++)
	{
		cout << a[i] << "," ;
	}
	cout << endl;
}

//插入排序
int * insertionSort(int *a,int len) {

	int historyIndex = 1;
	//int length = sizeof(a) ;


	for (int i = 0; i < len; i++){

		historyIndex = i;

		if (i + 1 < len && a[i + 1] < a[i]) {

			int temp = a[i];
			a[i] = a[i + 1];
			a[i + 1] = temp;

			//在比较过程中若是满足了位置对换的条件,还需要对之前比较过的数进行再次比较,直到结束
			while (historyIndex > 0 && a[historyIndex] < a[historyIndex - 1]) {
				int temp = a[historyIndex];
				a[historyIndex] = a[historyIndex - 1];
				a[historyIndex - 1] = temp;
				historyIndex--;
			}

		}

	
	}

	return a;
}


结果输出

排序前
500,86,1,77,55,24,
排序后
1,24,55,77,86,500,

Github

https://github.com/zj614android/algorithm/blob/master/Insertion_sort/Insertion_sort/Insertion.cpp

Thanks

动图:https://visualgo.net/zh/sorting
刘望舒:http://liuwangshu.cn/algorithm/2-insert-hill.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值