1. 程式人生 > >排序演算法——插入排序

排序演算法——插入排序

直接插入排序

最簡單的排序方法。它的基本操作是將一個記錄插入到已經排好序的有序表中,從而得到一個新的、記錄增1的有序表。

把n個待排序的元素看成一個有序表和一個無序表,開始時有序表中只有一個元素,無序表中有n-1個元素;排序過程即每次從無序表中取出第一個元素,將它插入到有序表中,使之成為新的有序表,重複n-1次完成整個排序過程。

        0.初始狀態 3,1,5,7,2,4,9,6(共8個數)

     有序表:3;無序表:1,5,7,2,4,9,6

  1.第一次迴圈,從無序表中取出第一個數 1,把它插入到有序表中,使新的數列依舊有序

     有序表:1,3;無序表:5,7,2,4,9,6

  2.第二次迴圈,從無序表中取出第一個數 5,把它插入到有序表中,使新的數列依舊有序

     有序表:1,3,5;無序表:7,2,4,9,6

  3.第三次迴圈,從無序表中取出第一個數 7,把它插入到有序表中,使新的數列依舊有序

     有序表:1,3,5,7;無序表:2,4,9,6

  4.第四次迴圈,從無序表中取出第一個數 2,把它插入到有序表中,使新的數列依舊有序

     有序表:1,2,3,5,7;無序表:4,9,6

  5.第五次迴圈,從無序表中取出第一個數 4,把它插入到有序表中,使新的數列依舊有序

     有序表:1,2,3,4,5,7;無序表:9,6

  6.第六次迴圈,從無序表中取出第一個數 9,把它插入到有序表中,使新的數列依舊有序

     有序表:1,2,3,4,5,7,9;無序表:6

  7.第七次迴圈,從無序表中取出第一個數 6,把它插入到有序表中,使新的數列依舊有序

     有序表:1,2,3,4,5,6,7,9;無序表:(空)

程式:

//直接插入排序
//升序排序 
#include<stdio.h> 

void InsertSort(int *a,int n) 
{
	int i,j,tmp;
	for(i=1;i<n;i++)
	{
		if(a[i-1]>a[i])
		{
			tmp=a[i];
			j=i;
			while(j&&tmp<a[j-1])
			{
				a[j]=a[j-1];
				j--;
			}
			a[j]=tmp;
		}
	}
} 

int main()
{
	int i;
	int a[]={1,2,8,5,6,9,4,2,7,5};
	int n=sizeof(a)/sizeof(int);
	InsertSort(a,n);
	for(i=0;i<n;i++)
		printf("%d ",a[i]);
	return 0;
}

直接插入排序的時間複雜度是o(n2) ;

折半插入排序

由於直接插入排序的前方資料已經基本有序,有時順序查詢很費時。因而產生了“折半”查詢的排序。

程式:

//折半插入排序
//升序排列
#include<stdio.h>

using namespace std; 

void BInsertSort(int *a,int n)
{
	int i,j,low,high,m,tmp;
	for(i=1;i<n;i++)
	{
		if(a[i]<a[i-1])
		{
			low=0;
			high=i-1;
			tmp=a[i];
			m=(low+high)/2;			
			while(low<high)//最後low==high跳出時,m=low=high 
			{	            //因而總體來說,m最後記錄的是插入位置 
				if(tmp<a[m])
					high=m-1;
				else if(tmp>a[m])
					low=m+1;
				else
					break;	
				m=(low+high)/2;
			}
			for(j=i;j>m;j--)
				a[j]=a[j-1]; 
			a[j]=tmp;
		}
	}
} 

int main()
{
	int i;
	int a[]={4,5,9,6,3,8,2,8,2,8,6,6,5,4,2,8,9,5};
	int n=sizeof(a)/sizeof(int);
	BInsertSort(a,n);
	for(i=0;i<n;i++)
		printf("%d ",a[i]);
	return 0;
}

希爾排序

插入排序在基本有序的情況下效率挺高,希爾排序可使程式部分逐漸變得有序。

一. 演算法描述

希爾排序:將無序陣列分割為若干個子序列,子序列不是逐段分割的,而是相隔特定的增量的子序列,對各個子序列進行插入排序;然後再選擇一個更小的增量,再將陣列分割為多個子序列進行排序......最後選擇增量為1,即使用直接插入排序,使最終陣列成為有序。

增量的選擇:在每趟的排序過程都有一個增量,至少滿足一個規則 增量關係 d[1] > d[2] > d[3] >..> d[t] = 1 (t趟排序);根據增量序列的選取其時間複雜度也會有變化,這個不少論文進行了研究,在此處就不再深究;本文采用首選增量為n/2,以此遞推,每次增量為原先的1/2,直到增量為1;

下圖詳細講解了一次希爾排序的過程:

--------------------- 本文來自 love小仙 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/jianfpeng241241/article/details/51707618?utm_source=copy

程式碼:

//希爾排序(升序)
#include<stdio.h>

void ShellInsert(int *a,int n)
{
	int dk[]={5,3,1};
	int dk_len=sizeof(dk)/sizeof(int);
	int i,j,k,tmp1,tmp2;
	for(i=0;i<dk_len;i++)
	{
		for(j=0;j<dk[i];j++)
		{
			for(k=j+dk[i];k<n;k+=dk[i])
			{
				if(a[k]<a[k-dk[i]])
				{
					tmp1=k;
					tmp2=a[k];
					while(tmp1>j&&tmp2<a[tmp1-dk[i]])
					{
						a[tmp1]=a[tmp1-dk[i]];
						tmp1-=dk[i];
					}
					a[tmp1]=tmp2;
				} 
			}
		}
	}
} 

int main()
{
	int i;
	int a[]={8,2,5,8,7,4,2,6,3,85,62,5,4,3,2,22,25,87};
	int n=sizeof(a)/sizeof(int);
	ShellInsert(a,n);
	for(i=0;i<n;i++)
		printf("%d ",a[i]);
	return 0;
}

參考文章: