排序算法的补充

建议先去看看我之前写的基础排序算法

补充一:快排中partition函数的三种实现形式

1.hoare法---与第2种方法类似

int Partition1(int*a,int left,int right) {
	int keyi = left;
	while (left < right) {
		while (left < right && a[right] >= a[keyi])
			right--;
		while (left < right && a[left] <= a[keyi])
			left++;
		swap(&a[left],&a[right]);
	}
	swap(&a[keyi],&a[left]);
	return left;
}

2.挖坑法---也是基础排序算法里写的

int Partition2(int* a, int left, int right) {
	int key = a[left];
	while (left < right) {
		while (left < right && a[right] >= key)
			right--;
		a[left] = a[right];
		while (left < right && a[left] <= key)
			left++;
		a[right]=a[left];
	}
	a[left] = key;
	return left;
}

3.双指针法

int Partition3(int* a, int left, int right) {
    int keyi = left;
	int pre = left, cur = left + 1;
	while (cur <= right) {
		if (a[cur] < a[keyi]) {
			pre++;
			swap(&a[pre],&a[cur]);
		}
		cur++;
	}
	swap(&a[pre], &a[keyi]);
	return pre;
}

举个例子帮助大家理解一下双指针法

排序算法的补充_第1张图片

 补充二:快排的非递归写法(栈的实现可以参考我之前写的栈和队列的实现)

本质和树的先序遍历的非递归写法一样

void QuickSortNonR(int* a, int left, int right) {
	ST st;
	StackInit(&st);
    //存放区间
	StackPush(&st, right);
	StackPush(&st, left);
	while (!StackEmpty(&st)) {
		int left = StackTop(&st);
		StackPop(&st);
		int right = StackTop(&st);
		StackPop(&st);
		int mid = PartSort1(a, left, right);
		if (mid - 1 > left) {//保证区间合法
			StackPush(&st, mid - 1);
			StackPush(&st, left);
		}
		if (mid + 1 < right) {//保证区间合法
			StackPush(&st, right);
			StackPush(&st, mid+1);
		}
	}
	StackDestroy(&st);
}

补充三:快排的三路划分写法---解决有多个重复数字的情况

//三路划分
void QuickSort_T(int* a, int left, int right) {
	if (left >= right)//保证区间合法
		return;
	int L = left, R = right;
	int key = a[left];
	int cur = left + 1;
	while (cur <= right) {
		if (a[cur] < key) {
			swap(&a[cur], &a[L]);
			L++;
			cur++;
		}else if (a[cur] == key) {
			cur++;
		}else {
			swap(&a[R], &a[cur]);
			R--;
		}
	}
	QuickSort_T(a, left, L - 1);
	QuickSort_T(a, R + 1, right);
}

举个例子

排序算法的补充_第2张图片

 补充4:计数排序

void CountSort(int* a, int n) {
	int min = a[0], max = a[0];
	for (int i = 1; i < n; i++) {
		if (a[i] < min)min = a[i];
		if (a[i] > max)max = a[i];
	}
	int range = max - min + 1;
	int* count_a = (int*)malloc(sizeof(int) * range);
	memset(count_a, 0, sizeof(int) * range);
	for (int i = 0; i < n; i++) {
		count_a[a[i] - min]++;
	}
	for (int i = 0,k = 0; i < range; i++) {
		while(count_a[i]--) {
			a[k++] = i + min;
		}
	}
}

补充五:归并排序的小优化(递归)

void _MergeSort(int* a, int left, int right, int* tmp) {
	if (left >= right)
		return;
	//小区间优化
	if (right - left + 1 < 10) {
		InsertSort(a + left, right - left + 1);
		return;
	}
	int mid = left + (right - left) / 2;
	_MergeSort(a, left, mid, tmp);
	_MergeSort(a, mid+1,right, tmp);
	//这里只能分成[left,mid][mid+1,right](因为mid=(left+right)/2)
	//如果分成[left,mid-1][mid,right]
	//当left和right相差为1时,mid=left
	//那么dfs(left,right)
	//=>dfs(left,mid-1)    dfs(mid,right)
	//<=>dfs(left,left-1)  dfs(left,right)
	//<=>return            dfs(left,mid-1) dfs(mid,right)
	//很显然,死递归了,问题就是在于dfs(left,right)一直在不停的重复递归
	int L1 = left, R1 = mid;
	int L2 = mid + 1, R2 = right;
	int k = 0;
	while (L1 <= R1 && L2 <= R2) {
		if (a[L1] < a[L2]) {
			tmp[k++] = a[L1++];
		}else{
			tmp[k++] = a[L2++];
		}
	}
	while (L1 <= R1)tmp[k++] = a[L1++];
	while (L2 <= R2)tmp[k++] = a[L2++];
	memcpy(a + left, tmp, sizeof(int) * k);
}
//归并
void MergeSort(int* a, int n) {
	int* tmp = (int*)malloc(sizeof(int) * n);
	_MergeSort(a, 0, n - 1, tmp);
	free(tmp);
}

你可能感兴趣的:(排序算法,算法)