1. 程式人生 > >排序演算法---之交換排序(氣泡排序&快速排序-左右指標法,挖坑法,前後指標法)

排序演算法---之交換排序(氣泡排序&快速排序-左右指標法,挖坑法,前後指標法)

                                                      排序演算法----交換排序(氣泡排序&快速排序)

一、排序演算法分為:

1.插入排序(直接插入排序&希爾排序)

     2.選擇排序(直接選擇排序&堆排序)

     3.交換排序(氣泡排序&快速排序)

     4.歸併排序

----快速排序總共有三種方法:(1).左右指標法(2).挖坑法(3).前後指標法

二、幾種排序的效能比較

排序方法的比較

類別

排序方法

時間複雜度

空間複雜度

穩定性

平均情況

最好情況

最壞情況

輔助儲存

插入排序

直接插入

O(n2)

O(n)

O(n2)

O(1)

穩定

希爾排序

O(n1.3)

O(n)

O(n2)

O(1)

不穩定

選擇排序

直接選擇

O(n2)

O(n2)

O(n2)

O(1)

不穩定

堆排序

O(nlog2n)

O(nlog2n)

O(nlog2n)

O(1)

不穩定

交換排序

氣泡排序

O(n2)

O(n)

O(n2)

O(1)

穩定

快速排序

O(nlog2n)

O(nlog2n)

O(n2)

O(nlog2n)

不穩定

歸併排序

O(nlog2n)

O(nlog2n)

O(nlog2n)

O(n)

穩定

基數排序

O(d(r+n))

O(d(rd+n))

O(d(r+n))

O(rd+n)

穩定

注:基數排序中,n代表關鍵字的個數,d代表長度,r代表關鍵字的基數

三、氣泡排序

    1.程式碼

//氣泡排序
void BubbleSort(int* a,size_t n)
{
	assert(a);
	int end = n;
	while(end>0)
	{
		for(int i=0;i<end;++i)
		{
			if(a[i-1]>a[i])
			{
				swap(a[i-1],a[i]);
			}
		}
		--end;
	}
}
//列印函式
void PrintArray(int* a,size_t n)
{
	for(size_t i=0;i<n;++i)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;
}
//測試程式碼
void  BubbleSortTest()
{
	int a[]={2,5,4,0,9,3,6,8,7,1};
	PrintArray(a,sizeof(a)/sizeof(a[0]));
	BubbleSort(a,sizeof(a)/sizeof(a[0]));
	PrintArray(a,sizeof(a)/sizeof(a[0]));
}
2.時間複雜度:

    最好情況:O(n)

    最壞情況:O(n^2)

    平均情況:O(n^2)

    空間複雜度:O(1)

3.穩定性:穩定

四、快速排序

   方法一左右指標法

   演算法程式碼:

//方法一:左右指標法
int PartSort1(int* a,int left,int right)
{
	int key = a[right];
	int begin = left;//左右指標,下標
	int end = right;
	while(begin<end)
	{
		while(begin<end && a[begin]<=key)//從左邊找比key大的值
		{
			++begin;
		}
		while(begin<end && a[end]>=key)//從右邊找比key小的值
		{
			--end;
		}
		if(begin<end)
		{
			swap(a[begin],a[end]);
		}
		swap(a[begin],a[right]);
	}
	return a[begin];
}
void QuickSort1(int* a,int left,int right)
{
	assert(a);
	if(left<right)
	{
		int div = PartSort1(a,left,right);
		QuickSort1(a,left,div-1);
		QuickSort1(a,div+1,right);
	}
}
//列印函式
void PrintArray(int* a,size_t n)
{
	for(size_t i=0;i<n;++i)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;
}
//測試程式碼
void QuickSortTest()
{
    int a[]={2,5,4,0,9,3,6,8,7,1};
	PrintArray(a,sizeof(a)/sizeof(a[0]));
	QuickSort1(a,0,(sizeof(a)/sizeof(a[0]))-1);
	PrintArray(a,sizeof(a)/sizeof(a[0]));
}
    方法二:挖坑法

    演算法程式碼:

//方法二:挖坑
int PartSort2(int* a,int left,int right)
{
	int key = a[right];
	while(left<right)
	{
		while(left<right && a[left]<=key)
		{
			++left;
		}
		a[right] = a[left];//左坑
		while(left<right && a[right]>=key)
		{
			--right;
		}
		a[left] = a[right];
	}
	a[left] = key;
	return a[left];
}
void QuickSort2(int* a,int left,int right)
{
	assert(a);
	if(left<right)
	{
		int div = PartSort2(a,left,right);
		QuickSort2(a,left,div-1);
		QuickSort2(a,div+1,right);
	}
}
//列印函式
void PrintArray(int* a,size_t n)
{
	for(size_t i=0;i<n;++i)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;
}
//測試程式碼
void QuickSortTest()
{
    int a[]={2,5,4,0,9,3,6,8,7,1};
	PrintArray(a,sizeof(a)/sizeof(a[0]));
	QuickSort2(a,0,(sizeof(a)/sizeof(a[0]))-1);
	PrintArray(a,sizeof(a)/sizeof(a[0]));
}
      方法三:前後指標法

     演算法程式碼:

//方法三:前後指標法??若有問題,請指出
int PartSort3(int* a,int left,int right)
{
	int cur = left;
	int prev = left-1;
	int key = a[right];
	while(cur<right);
	{
		if(a[cur]<key && ++prev!=cur)
		{
			swap(a[cur],a[prev]);
		}
		++cur;
	}
	swap(a[++prev],a[right]);
	return prev;
}

void QuickSort3(int* a,int left,int right)
{
	assert(a);
	if(left<right)
	{
		int div = PartSort3(a,left,right);
		QuickSort3(a,left,div-1);
		QuickSort3(a,div+1,right);
	}
}
//列印函式
void PrintArray(int* a,size_t n)
{
	for(size_t i=0;i<n;++i)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;
}
//測試程式碼
void QuickSortTest()
{
    int a[]={2,5,4,0,9,3,6,8,7,1};
	PrintArray(a,sizeof(a)/sizeof(a[0]));
	QuickSort3(a,0,(sizeof(a)/sizeof(a[0]))-1);
	PrintArray(a,sizeof(a)/sizeof(a[0]));
}
2.時間複雜度:

   最好情況:O(nlogn)

   最壞情況:O(n^2)

   平均情況:O(nlogn)

   空間複雜度:O(nlogn)

3.穩定性:不穩定