1. 程式人生 > >各種排序演算法分析與比較

各種排序演算法分析與比較

1.直接插入排序

每一趟將一個待排序的元素作為關鍵字,按照其關鍵字的大小插入到已經排好的部分序列的適當位置上。平均時間複雜度為O(n2),空間複雜度為O(1)。

void InsertSort(int R[], int n)
{
	if (R == nullptr || n<=0)
		return;
	int i, j;
	int temp;
	for (i = 1; i < n; ++i)
	{
		j = i - 1;
		temp = R[i];
		while (j >= 0 && R[j] > temp)
		{
			R[j+1] = R[j];
			--j;
		}
		R[j+1] = temp;
	}
}

2.氣泡排序

平均時間複雜度為O(n2),空間複雜度為O(1)

void BubbleSort(int R[], int n)
{
	if (R == nullptr || n <= 0)
		return;
	int i, j;
	int temp;
	int flag = 0;
	for (i = n; i >= 1; --i)
	{
		flag = 0;//每次重新置為0
		for (j = 1; j < i; ++j)
		{
			if (R[j - 1] > R[j])
			{
				temp = R[j];
				R[j] = R[j - 1];
				R[j - 1] = temp;
				flag = 1;//有資料交換,flag=1;
			}
		}

		if (flag == 0)
			return;
	}
}

3.快速排序

快速排序以樞軸為中心,將序列分成兩部分。關鍵是樞軸的劃分。

時間複雜度:最好的情況下為O(nlogn),最壞為O(n2)

空間複雜度:O(log2n)

遞迴演算法:

void QuickSort(int R[], int low, int high)
{
	if (low >= high)
		return;
	int pivot = Partition(R, low, high);
	QuickSort(R, low, pivot - 1);
	QuickSort(R, pivot + 1, high);
}
幾種劃分演算法:

1.從後往前掃描直到小於樞軸的位置j,將R[j]交換到i的位置;從i開始往後掃描,直到遇到大於樞軸的位置i,把R[i]交換到j的位置。

int Partition(int R[], int low, int high)
{
	int pivot = R[low];
	while (low < high)
	{
		while (low < high && R[high] >= pivot)
			--high;
		if (low < high)
			R[low] = R[high];
		while (low < high && R[low] <= pivot)
			++low;
		if (low < high)
			R[high] = R[low];
	}
	R[low] = pivot;
	return low;
}
2.從前往後掃描,遇到小於樞軸的值,則遞增small值,如果當前下標與small不相等,則交換,保證small左邊的元素都小於樞軸。
int Partition(int data[], int start, int end)
{
	int index= RandomInRange(start,end);//隨機生成一個數作為中樞值
	swap(data[index],data[end]);//最後一個值作為中樞值
	
	int small=start-1;
	for(index=start; index<end; ++index)
	{
		if(data[index]<data[end])
		{
			++small;
			if(small != index)
				swap(data[index], data[small]);
		}
	}
	++small;
	swap(data[small], data[end]);
	return small;
}

3.兩邊同時進行掃描,並交換位置。

int Partition3(int R[], int low, int high)
{
	int pivot = R[low];
	int i = low + 1;
	int j = high;
	while (i <= j)
	{
		while (i <= j && R[j] >= pivot)
			--j;
		while (i <= j && R[i] <= pivot)
			++i;
		if (i < j)
		{
			swap(R[i], R[j]);
			++i;
			--j;
		}
	}
	swap(R[low], R[j]);
	return j;
}

4.堆排序

堆是一種資料結構,可以把堆看成完全二叉樹,這棵完全二叉樹滿足:任何一個非葉節點的值都不大於(或不小於)其左右孩子節點的值。若父節點大於孩子節點,則叫大頂堆,父節點小於孩子節點,則叫小頂堆。

堆排序的主要操作是將序列調整為堆。

時間複雜度:O(n log2n);空間複雜度:O(1)

void Shift(int R[], int low, int high)
{
	int i = low;
	int j = 2 * i + 1;
	int temp = R[i];
	while (j <= high)
	{
		if (j < high && R[j] < R[j + 1])
		{
			++j;
		}
		if (temp < R[j])
		{
			R[i] = R[j];
			i = j;
			j = 2 * i + 1;
		}
		else
			break;
	}
	R[i] = temp;
}
void HeapSort(int R[], int n)
{
	int i;
	int temp;
	for (i = n / 2 - 1; i >= 0; --i)
	{
		Shift(R, i,n);
	}
	for (i = n-1; i >= 1; --i)
	{
		temp = R[0];
		R[0] = R[i];
		R[i] = temp;
		Shift(R, 0, i - 1);
	}
}

4.二路歸併排序

歸併排序的時間複雜度和初始序列無關,平均情況下為O(n log2n),最好情況下為O(nlog2n),最壞情況下也為O(nlog2n)。

空間複雜度:因歸併排序需要轉存整個待排序列,因此空間複雜度為O(n)

void Merge(int R[], int tempArray[], int low, int mid, int high)
{
	int i = low;
	int j = mid + 1;
	int k = i;
	while (i <= mid && j <= high)
	{
		if (R[i] < R[j])
			tempArray[k++] = R[i++];
		else
			tempArray[k++] = R[j++];
	}
	while (i <= mid)
		tempArray[k++] = R[i++];
	while (j <= high)
		tempArray[k++] = R[j++];
	for (int i = low; i <= high; ++i)
	{
		R[i] = tempArray[i];
	}
}
void MergeSort(int R[],int tempArray[], int low, int high)
{
	if (low < high)
	{
		int mid = (low + high) / 2;
		MergeSort(R, tempArray, low, mid);
		MergeSort(R, tempArray, mid + 1, high);
		Merge(R, tempArray, low, mid, high);
	}
}
void MergeSort(int R[], int n)
{
	int *tempArray = new int[n];
	MergeSort(R, tempArray, 0, n - 1);
	delete []tempArray;
}
5.計算排序

適用於元素的取值範圍比較小的情況。

1>統計每個元素的個數

2>統計每個元素比自身小的元素個數

template <typename Type>
void CountingSort(Type array[], int low, int high, int range)//range為元素的取值範圍
{
	Type *result = new Type[high - low + 1];
	Type *valueCount = new Type[range + 1];

	for (int i = 0; i <= range; ++i)
	{
		valueCount[i] = 0;
	}

	for (int i = low; i <= high; ++i)
	{
		valueCount[array[i]] += 1;
	}

	for (int i = 1; i <= range; ++i)
	{
		valueCount[i] += valueCount[i - 1];
	}

	for (int i = high; i >= low; --i)
	{//form high to low , in order to guarantee the stable sort
		result[valueCount[array[i]] - 1] = array[i];
		--valueCount[array[i]];
	}
	
	int i = low;
	while (i <= high)
	{
		array[i] = result[i - low];
		++i;
	}

	delete[] result;
	delete[] valueCount;
}

參考部落格: