排序(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).

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