1. 程式人生 > >七種基本排序思考

七種基本排序思考


 

 

//插排
//穩定
//時間複雜度【最差情況】:O(n^2)
//空間複雜度:O(1)
void InsertSort(int array[], int size)
{
	int key;
	int i, j;
	for (i = 1; i < size; i++){
		key = array[i];
		for (j = i - 1; j >= 0; j--){
			if (key >= array[j]){
				break;
			}
			else{
				array[j + 1] = array[j];
			}
		}
		array[j + 1] = key;
	}
}

 


 

void _InsertSort(int array[], int size, int gap)
{
	for (int g = 0; g < gap; g++){
		int key;
		int i, j;
		for (i = gap + g; i < size; i += gap){
			key = array[i];
			for (j = i - gap; j >= 0; j -= gap){
				if (key >= array[j]){
					break;
				}
				else{
					array[j + gap] = array[j];
				}
			}
			array[j + gap] = key;
		}
	}
}

//希排
//1 不穩定
//2 時間複雜度【最差情況】: O(n^2)
void ShellSort(int array[], int size)
{
	int gap = size;
	while (1){
		gap = gap / 3 + 1;
		_InsertSort(array, size, gap);
		if (gap == 1){
			break;
		}
	}
}

 


 

void Swap(int *a, int *b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

//不穩定
//時間複雜度   O(n^2)
//選擇排序1(每次選擇最大的放到最後)
void SelectSort(int array[], int size)
{
	//i代表每次還剩多少個數,當剩下一個數的時候,就不要移動了
	for (int i = size; i > 1; i--){
		int max = 0;//最大值下標
		for (int j = 1; j < i; j++){
			if (array[j] > array[max]){
				max = j;
			}
		}
		Swap(array + max, array + i - 1);
	}
}

//選擇排序2(每次選擇最大的放到最後,同時選擇最小的放到最前邊)
void SelectSrotOP(int array[], int size)
{
	int left = 0, right = size - 1;
	while (left < right)
	{
		int min = left, max = left;
		for (int j = left + 1; j <= right; j++){
			if (array[j] > array[max]){
				max = j;
			}
			if (array[j] < array[min]){
				min = j;
			}
		}
		Swap(array + left, array + min);
		//注意!!!
		if (max == left){//此時說明最大值下標就是left下標元素
			max = min;//此時最大值已經被交換到下標為min了,所以max應該移到min處
		}
		Swap(array + right, array + max);
		left++; right--;
	}
}

 


 

 

void AdjustDown(int array[], int size, int root)
{
	int left = 2 * root + 1;//左孩子下標
	int right = 2 * root + 2;//右孩子下標

	if (left >= size){
		return;//沒有左孩子(右孩子也肯定沒有)
	}

	int max = left;
	if (right < size && array[right] > array[left]){
		max = right;
	}//有孩子,判斷大孩子下標

	if (array[root] >= array[max]){
		return;//如果雙親節點大於大孩子,不用調整
	}

	Swap(array + root, array + max);//交換大孩子和雙親節點
	AdjustDown(array, size, max);
}


void CreateHeap(int array[], int size)
{
	//從最後一個非葉子節點
	//不斷向下調整
	for (int i = (size - 1) / 2; i >= 0; i--){
		AdjustDown(array, size, i);
	}
}

//堆排
//不穩定
//時間複雜度 O(N*logN)
void HeapSort(int array[], int size)
{
	//1 建大堆(升序)(找最大值)
	CreateHeap(array, size);

	for (int i = 0; i < size - 1; i++){
		Swap(&array[0], &array[size - 1 - i]);
		AdjustDown(array, size - i - 1, 0);
	}
}

 

 


 

//氣泡排序
//穩定
//時間複雜度 O(N^2)
void BubbleSort(int array[], int size)
{
	for (int i = 0; i < size - 1; i++){
		int isSorted = 1;
		for (int j = 0; j < size - 1 - i; j++){
			if (array[j] > array[j + 1]){
				Swap(array + j, array + j + 1);
				isSorted = 0;
			}
		}
		if (1 == isSorted){
			break;
		}
	}
}

 


 

//快排小的放左、大的放右【左右指標法】
//時間複雜度 O(N)
int Partition_01(int array[], int left, int right)//基準值的下標
{
	int begin = left;//不是0
	int end = right; //不是right-1

	while (begin < end){
		//如果基準值在最右邊,先動begin
		while (begin < end && array[begin] <= array[right]){
			begin++;//第二次比較左右下標,防止所有元素都小於基準值,
		}
		while (begin < end && array[end] >= array[right]){
			end--;//第二次比較左右下標,防止所有元素都大於基準值,
		}
		Swap(array + begin, array + end);
	}
	Swap(array + begin, array + right);

	return begin;//基準值
}

//快排
//時間複雜度 O(N*logN)   最壞情況就是單枝樹O(N^2)
//空間複雜度 O(logN)      O(N)
//array [left, right]
//左閉右閉
void _QuickSort(int array[], int left, int right)
{
	if (left >= right){
		return;
	}

	int div = Partition_02(array, left, right);//基準值的下標
	
	_QuickSort(array, left, div - 1);  //[left, div-1]
	_QuickSort(array, div + 1, right); //[div+1, right]
}

void  QuickSort(int array[], int size)
{
	_QuickSort(array, 0, size - 1);
}

 

 

 

//快排小的放左、大的放右【左右挖坑法】
//時間複雜度 O(N)
int Partition_02(int array[], int left, int right)
{
	int begin = left;
	int end = right;
	int pivot = array[right];//pivot 存的就是基準值

	while (begin < end){
		while (begin < end && array[begin] <= pivot){
			begin++;
		}
		array[end] = array[begin];//補右坑==挖左坑
		while (begin < end && array[end] >= pivot){
			end--;
		}
		array[begin] = array[end];//補左坑==挖右坑
	}
	array[begin] = pivot;

	return begin;
}

//快排
//時間複雜度 O(N*logN)   最壞情況就是單枝樹O(N^2)
//空間複雜度 O(logN)      O(N)
//array [left, right]
//左閉右閉
void _QuickSort(int array[], int left, int right)
{
	if (left >= right){
		return;
	}

	int div = Partition_02(array, left, right);//基準值的下標
	
	_QuickSort(array, left, div - 1);  //[left, div-1]
	_QuickSort(array, div + 1, right); //[div+1, right]
}

void  QuickSort(int array[], int size)
{
	_QuickSort(array, 0, size - 1);
}

 

 

//快排小的放左、大的放右【前後指標】
//時間複雜度 O(N)
int Partition_03(int array[], int left, int right)
{
	int div = left;
	int cur = left;

	while (cur < right){
		if (array[cur] < array[right]){
			Swap(array + cur, array + div);
			div++;
		}
		cur++;
	}

	Swap(array + div, array + right);
	return div;
}

//快排
//時間複雜度 O(N*logN)   最壞情況就是單枝樹O(N^2)
//空間複雜度 O(logN)      O(N)
//array [left, right]
//左閉右閉
void _QuickSort(int array[], int left, int right)
{
	if (left >= right){
		return;
	}

	int div = Partition_03(array, left, right);//基準值的下標
	
	_QuickSort(array, left, div - 1);  //[left, div-1]
	_QuickSort(array, div + 1, right); //[div+1, right]
}

void  QuickSort(int array[], int size)
{
	_QuickSort(array, 0, size - 1);
}

附加講解:(快排不穩定)

選擇基準值的方法:1)最邊上(最左、最右)

                                 2)隨機

                                 3)三數取中

 


 

 

 

 

void Merge(int array[], int left, int mid, int right, int *extra)
{
	int left_i = left;
	int right_i = mid;
	int extra_i = left;

	while (left_i < mid && right_i < right){
		if (array[left_i] <= array[right_i]){
			extra[extra_i++] = array[left_i++];
		}
		else{
			extra[extra_i++] = array[right_i++];
		}
	}

	while (left_i < mid){
		extra[extra_i++] = array[left_i++];
	}

	while (right_i < right){
		extra[extra_i++] = array[right_i++];
	}

	for (int i = left; i < right; i++){
		array[i] = extra[i];
	}
}

//歸併排序
//時間複雜度 O(N*logN)  
//空間複雜度 O(N)       
//array [left, right)
//左閉右開
void _MergeSort(int array[], int left, int right, int *extra)
{
	if (left == right - 1){
		return;//[0,1)
	}
	if (left >= right){
		return;//區間沒有數了
	}

	int mid = left + (right - left) / 2;
	_MergeSort(array, left, mid, extra);//[left, mid)//左邊排有序
	_MergeSort(array, mid, right, extra);//[mid,  right)//右邊排有序
	Merge(array, left, mid, right, extra);//整體合併成有序
}

void  MergeSort(int array[], int size)
{
	int *extra = (int *)malloc(size * sizeof(int));
	_MergeSort(array, 0, size, extra);//左閉右開
	free(extra);
}

歸排穩定

 

 


總結: