排序(3) -插入排序 (图文演示)

所有的排序都以升序为例。考虑复杂度,考虑稳定性的情况。以及在原基础上步步的优化。

插入排序:
插入排序非常类似于扑克牌排序。

算法:
**1.在执行过程中,插入排序会把序列分为2部分。其中头部是已经排好序的,尾部是待排序的。
**2.从头开始扫描每一个元素。每当扫描到一个元素,就把它插入到头部合适的位置,使得头部数据依然保持有序。


图片实例:
在这里插入图片描述


插入排序:
算法:待排序的序列与已经排序好的序列比较进行比较,如果待排序序列比已经排好序的序列小,就交换位置。

void InsertionSort::sort(int array[], int len)
{
	if (array == NULL|| len < 2)
	{
		return;
	}

	this->m_array = array;
	this->m_len = len;


	for (int begin = 1; begin < this->m_len; begin++)
	{
		//默认:第一个元素是有序的
		int cur = begin;
		while (cur > 0 && cmp(cur, cur - 1) < 0)
		{
			this->swap(cur, cur - 1);
			cur--;
		}
	}

	for (int i = 0; i < this->m_len; i++)
	{
		cout << this->m_array[i] << "_";
	}

}

逆序对(inversion)
什么是逆序对?
比如数组[2,3,8,6,1]的逆序对是[2,1], [3,1],[8,1],[8,6],[6,1]共5个逆序对。

插入排序的时间复杂度与逆序对的数量成正比关系。


插入排序优化1:
思路:将交换转为挪动。(省去不停的交换过程)
**1.先将待交换的元素备份
**2.头部有序的数据头部有序的数据中比待插入元素大的,都朝着尾部方向挪动一个位置。
**3.将待插入的元素放在合适的位置

在这里插入图片描述

void InsertionSort1::sort(int array[], int len)
{
	if (array == NULL || len < 2)
	{
		return;
	}

	this->m_array = array;
	this->m_len = len;

	for (int begin = 1; begin < this->m_len; begin++)
	{
		int cur = begin;
		//备份待排序元素
		int v = this->m_array[cur];
		while (cur > 0 && this->cmpElements(v, array[cur -1]) < 0)
		{
			//挪动数组元素
			this->m_array[cur] = this->m_array[cur - 1];
			cur--;
		}
		this->m_array[cur] = v;
	}


	for (int i = 0; i < this->m_len; i++)
	{
		cout << this->m_array[i] << "_";
	}
}

插入排序 - 二分搜索优化3
1.在元素v的插入过程中,可以使用二分搜索出合适的插入位置,然后再将元素V插入。
在这里插入图片描述
二分搜索:
在这里插入图片描述
举例:
在这里插入图片描述


插入排序:

void InsertionSort2::sort(int array[], int len)
{
	if (array == NULL || len < 2)
	{
		return;
	}

	this->m_array = array;
	this->m_len = len;

	for (int begin = 1; begin < this->m_len; begin++)
	{
		int v = this->m_array[begin];
		int insertIndex = search(begin);
		//将[insertIndex,begin)范围内的元素往右挪动一个单位
		//挪动方法一:
		for (int i = begin; i > insertIndex; i--)
		{
			this->m_array[i] = this->m_array[i - 1];
		}

		//挪动方法二:
		/*for (int i = begin - 1; i >= insertIndex; i--)
		{
			this->m_array[i + 1] = this->m_array[i];
		}*/
		this->m_array[insertIndex] = v;
	}


	for (int i = 0; i < this->m_len; i++)
	{
		cout << this->m_array[i] << "_";
	}
}

根据二分搜索找到合适的插入的位置:

//利用二分搜索找到 index 位置元素的待插入位置
//index中所包含的信息有:已经排好序的元素个数。[0,index);
int InsertionSort2::search(int index)
{
	int v = this->m_array[index];

	int begin = 0;
	int end = index;

	while (begin < end)
	{
		int mid = (begin + end) >> 1;
		if (this->cmpElements(v,this->m_array[mid]) < 0)
		{
			end = mid;
		}
		else
		{
			begin = mid + 1;
		}
	}
	return begin;
}

总结:使用二叉搜索后,只是减少了比较的次数,但插入排序的平均时间复杂度依然是O(n^2).

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章