C語言中常見的排序方法(插入排序、希爾排序、選擇排序、堆排序、冒泡排序、快速排序)

插入排序

void PrintArray(int* a, int n)
{
	for (size_t i = 0; i < n; ++i)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
	
}

void InsertSort(int* a, int n)
{
	// 控制end的位置從0走到n-2
	for (int i = 0; i < n - 1; ++i)
	{
		// 單趟排序
		// 在[0,end]區間中插入tmp,依舊有序
		int end = i;
		int tmp = a[end + 1];
		while (end >= 0)
		{
			if (a[end] > tmp)
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

void TestInsertSort()
{
	int a[] = { 3, 6, 2, 5, 7, 9, 8, 6, 1, 4 };
	InsertSort(a, sizeof(a) / sizeof(int));
	PrintArray(a, sizeof(a) / sizeof(int));
}

希爾排序

// 平均時間複雜度:O(N^1.3)  什麼情況下最壞:順序有序(預排序全部白做了,還不如直接插入排序)
void ShellSort(int* a, int n)
{
	// gap > 1時爲預排序         接近有序
	// gap == 1時爲直接插入排序  有序
	int gap = n;
	while (gap > 1)
	{
		// 間隔爲gap的預排序
		gap = gap / 3 + 1;  // +1是保證最後一次一定是1
		for (int i = 0; i < n - gap; ++i)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}

			a[end + gap] = tmp;
		}
	}
}

void TestShellSort()
{
	int a[] = { 3, 6, 2, 5, 7, 9, 8, 6, 1, 4 };
	ShellSort(a, sizeof(a) / sizeof(int));
	PrintArray(a, sizeof(a) / sizeof(int));
}

選擇排序

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

// 時間複雜度 O(N*N)
void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;
	while (begin < end)
	{
		// [begin, end] 選出一個最小的,選出一個最大的下標
		int mini = begin, maxi = end;
		for (int i = begin; i <= end; ++i)
		{
			if (a[i] > a[maxi])
				maxi = i;

			if (a[i] < a[mini])
				mini = i;
		}
		Swap(&a[begin], &a[mini]);
		// 修正
		if (begin == maxi)
			maxi = mini;

		Swap(&a[end], &a[maxi]);

		//printf("[%d,%d]", begin, end);
		//PrintArray(a, n);

		++begin;
		--end;	
	}
}

void TestSelectSort()
{
	int a[] = { 3, 6, 2, 5, 7, 9, 8, 6, 1, 4 };
	// int a[] = { 9, 6, 2, 5, 7, 3, 8, 6, 1, 4 };
	SelectSort(a, sizeof(a) / sizeof(int));
	PrintArray(a, sizeof(a) / sizeof(int));
}

堆排序

void AdjustDwon(int* a, int n, int root)
{
	int parent = root;
	int child = parent * 2 + 1;
	while (child < n)
	{
		// 選出左右孩子中大的那一個
		if (child+1 < n && a[child+1] > a[child])
		{
			++child;
		}

		// 1、如果孩紙比父親大,交換,繼續向下調整
		// 2、如果孩紙小於父親,則調整結束
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

// O(N*LogN)
void HeapSort(int* a, int n)
{
	// 排升序,建大堆
	// O(N)
	for (int i = (n-1-1)/2; i >= 0; --i)
	{
		AdjustDwon(a, n, i);
	}

	int end = n - 1;
	while (end > 0)
	{
		// 把堆頂當前最大數一次換到最後
		Swap(&a[0], &a[end]);
		// 調堆選出剩下的數當中最大
		AdjustDwon(a, end, 0);
		--end;
	}
}

void TestHeapSort()
{
	int a[] = { 3, 6, 2, 5, 7, 9, 8, 6, 1, 4 };
	// int a[] = { 9, 6, 2, 5, 7, 3, 8, 6, 1, 4 };
	HeapSort(a, sizeof(a) / sizeof(int));
	PrintArray(a, sizeof(a) / sizeof(int));
}

冒泡排序

void BubbleSort(int* a, int n)
{
	// 單趟排序
	for (int end = n - 1; end > 0; --end)
	{
		int flag = 0;
		for (int i = 0; i < end; ++i)
		{
			if (a[i] > a[i + 1])
			{
				Swap(&a[i], &a[i + 1]);
				flag = 1;
			}
		}

		if (flag == 0)
		{
			break;
		}
	}
}

void TestBubbleSort()
{
	int a[] = { 3, 6, 2, 5, 7, 9, 8, 6, 1, 4 };
	// int a[] = { 9, 6, 2, 5, 7, 3, 8, 6, 1, 4 };
	BubbleSort(a, sizeof(a) / sizeof(int));
	PrintArray(a, sizeof(a) / sizeof(int));
}

快速排序

// hoare法
int HoareMethod(int* a, int begin, int end)
{
	// end做key,左邊先走 / begin做key,右邊先走
	int key = a[end];
	int keyindex = end;
	while (begin < end)
	{
		// begin找大
		while (begin < end && a[begin] <= key)
			++begin;

		// end找小
		while (begin < end && a[end] >= key)
			--end;

		Swap(&a[begin], &a[end]);
	}

	Swap(&a[begin], &a[keyindex]);

	return begin;
}

// 挖坑法 相比於hoare,有一些改進,理解起來更容易,且不容易犯錯
int DigHoleMethod(int* a, int begin, int end)
{
	int key = a[end];
	while (begin < end)
	{
		// 找大
		while (begin < end && a[begin] <= key)
			++begin;
		a[end] = a[begin]; // 找到大扔到右邊的坑裏面去,同時end形成新的坑位

		while (begin < end && a[end] >= key)
			--end;
		a[begin] = a[end]; // 找到小扔到左邊的坑裏面去,同時begin形成新的坑位
	}

	a[begin] = key;
	return begin;
}

// 前後指針版本 邏輯抽象,但是實現很簡潔
int PrevCurMethod(int* a, int begin, int end)
{
	int prev = begin-1;
	int cur = begin;
	int key = a[end];

	while (cur < end) // 遇到key的位置就結束了
	{
		if (a[cur] < key && ++prev != cur)
			Swap(&a[prev], &a[cur]);
		++cur;
	}
	++prev;
	Swap(&a[prev], &a[end]);

	return prev;
}

void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;

	int keyindex = PrevCurMethod(a, begin, end);
	// [begin, keyindex-1]  key  [keyindex+1,end]
	QuickSort(a, begin, keyindex - 1);
	QuickSort(a, keyindex+1, end);
}

void TestQuickSort()
{
	int a[] = { 3, 3, 2, 5, 7, 9, 8, 6, 1, 5 };
	QuickSort(a, 0, sizeof(a) / sizeof(int)-1);
	PrintArray(a, sizeof(a) / sizeof(int));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章