1. 程式人生 > >C++ 插入排序演算法的實現與改進(含筆試面試題)

C++ 插入排序演算法的實現與改進(含筆試面試題)

      插入排序是一種最簡單直觀的排序演算法,它的工作原理是通過構建有序序列,對於未排序資料,在已排序序列中從後向前掃描,找到相應位置並插入。

簡單小tips:假設一個數列:1、2、5、3。插入排序的思想就是從1開始每次向前遍歷:

2比1大,為有序

5比2大,5比1大,為有序

3比5小,無序,交換,交換之後3與2比,3與1比有序

結果為 :1、2、3、5


演算法步驟:

1)將第一待排序序列第一個元素看做一個有序序列,把第二個元素到最後一個元素當成是未排序序列。

2)從頭到尾依次掃描未排序序列,將掃描到的每個元素插入有序序列的適當位置。(如果待插入的元素與有序序列中的某個元素相等,則將待插入元素插入到相等元素的後面。)

實現程式碼:過載插入排序的函式,一次的改進:二分法查詢插入位置

/***************************************************************************
 *  @file       main.cpp
 *  @author     MISAYAONE
 *  @date       24  March 2017
 *  @remark     24  March 2017 
 *  @theme      Insertion Sort 
 ***************************************************************************/

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

//傳入一對迭代器,標準的插入排序
void Insertion_sort(vector<int>::iterator begin,vector<int>::iterator end)
{
	for (auto p1 = begin; p1 != end; ++p1)
	{
		auto p2 = p1;
		while ((p2 != begin) && *(p2-1)>*p2)
		{
			int temp = *(p2);
			*p2 = *(p2-1);
			*(p2-1) = temp;
			--p2;
		}
	}
}

//對函式進行過載,傳入指向陣列的指標和陣列大小,同時進行第一次改進(也稱二分插入排序)
void Insertion_sort(int a[],size_t size)
{
	for (size_t i = 1; i != size; ++i)
	{
		int low  = 0;//排好元素的下界
		int high = i;//排好元素的上界
		if (a[i-1] > a[i])//判斷元素是否需要排序,滿足條件則需要排序
		{
			int temp = a[i];//待排元素
			a[i] = a[i-1];//直接先將排好元素中的最後一個元素後移一位
			//while迴圈使用二分法找到插入位置
			while (low <= high)
			{
				int mid = (low+high)/2;
				if (temp < a[mid])//待排元素之前的序列肯定是有序的,找到其中位數比較大小
				{
					high = mid-1;			
				}
				else
					low = mid+1;		
			}
			size_t j=i-1;
			for(j;j>=high+1;j--)//移動元素
				a[j+1]=a[j];  
			a[j+1] = temp; 
		}
	}
}


int main(int argc, char **argv)
{
	int a[10] = {2,5,6,3,1,4,8,7,9,0};
	vector<int> vec(a,a+10);

	Insertion_sort(vec.begin(),vec.end());
	for (size_t i = 0; i < vec.size(); ++i)
	{
		cout<<vec[i]<<" ";
	}

	Insertion_sort(a,10);
	cout<<endl;
	for (size_t i = 0; i < 10; ++i)
	{
		cout<<a[i]<<" ";
	}

	cin.get();
	return 0;
}

複雜度分析:

最優時間複雜度:當輸入陣列就是排好序的時候,複雜度為O(n),而快速排序在這種情況下會產生O(n^2)的複雜度。
最差時間複雜度:當輸入陣列為倒序時,複雜度為O(n^2)

插入排序比較適合用於“少量元素的陣列”

插入排序的複雜度和逆序對的個數一樣,當陣列倒序時,逆序對的個數為n(n-1)/2,因此插入排序複雜度為O(n^2)。

特點分析:穩定演算法(stable)、in place演算法

例題1:請寫出連結串列的插入排序程式:

template<typename T>  
struct list_node  
{  
    struct list_node<T> *next;  
    T value;  
};  
template<typename T>  
struct _list  
{  
    struct list_node<T> *head;  
    int size;  
};  
template<typename T>  
void SortLink(struct _list<T> * link) {  
    struct list_node<T> *pHead,*pRear,*p,*tp;  
    if (!link) return;  
    for (pHead=link->head,pRear=0;pHead;pHead=pHead->next) {  
        for (tp=pHead,p=pHead->next;p;tp=p,p=p->next)  
            if (pHead->value>=p->value)  
                tp->next=p->next,p->next=pHead,pHead=p,p=tp;  
        if (!pRear) link->head=pHead;  
        else pRear->next=pHead;  
        pRear=pHead;  
    }  
}