交换排序、归并排序、计数排序

冒泡排序:

void BubbleSort(int* a, int n)
{//第一层循环是趟数,第二层是交换
	for (int i = 0; i <= n-2; i++)
	{
		int flag = 0;
		for (int j = 0; j <= n - 2 - i; j++)
		{
			if (a[j] > a[j + 1])
			{
				swap(&a[j], &a[j + 1]);
				flag = 1;
			}
		}
		if (flag == 0)
		{
			break;
		}
}
}

这里做了一个小优化,通过flag的值来减少运行趟数,防止已经有序的情况下继续比较,最坏时间复杂度N方,最好时间复杂度o(N) ,具有稳定性

快速排序:

void _QuickSort1(int* a, int left, int right)
{
	int key = left; 
	int begin = left, end = right;
	if (begin >=end)
	{
		return;
	}
	三数取中法
	//int mid =Getmid(a, left, right);
	//swap(&a[left], &a[mid]);
	//随机数法
	//int randi = rand() % (right - left) + left;
	//swap(&a[randi], &a[left]);
	while (begin<end)
	{
		while (begin<end)
		{
			if (a[key] <= a[end])//一定保证右边先走
			{
				end--;
			}
			else
			{
				break;
			}

		}
		while (begin<end)
		{
			if (a[key] >=a[begin])
			{
				begin++;
			}
			else
			{
				break;
			}
		}
		swap(&a[begin], &a[end]);
	}
	swap(&a[left], &a[begin]);
	 key = begin;
	_QuickSort1(a, 0, key - 1);
	_QuickSort1(a, key + 1, right);
}

快排时间复杂度是o(nlogn),但是当整个数组为有序序列时,快排时间复杂度就为N方,所以这里有三数取中法和随机数法, 使key的值变得随机,这里更推荐三数取中,因为交换后所得到的值肯定为中间值,但有一种特殊情况,就是整个数列中的数都为同一个值,这时候时间复杂度只能为N方,具有不稳定性

三数取中法

int Getmid(int* a, int left, int right)
{
	int mid = (left + right) / 2;
	if (a[left] > a[mid])
	{
		if (a[mid] > a[right]) {
			return mid;
		}
		else if (a[left] > a[right])
		{
			return right;
		}
		else
		{
			return left;
		}
	}
	else
	{
		if (a[left] > a[right])
		{
			return left;
		}
		else if (a[right] < a[mid])
		{
			return right;
		}
		else
		{
			return mid;
		}

	}
}

随机数法 

//随机数法
	//int randi = rand() % (right - left) + left;

快排双指针法:

void _QuickSort2(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	int key = left;
	int prev = left;
	int cur = left+1;
	while (cur <= right)
	{
		if (a[cur] < a[key] && ++prev != cur)
		{
			swap(&a[prev], &a[cur]);
		}
		cur++;
	}
	swap(&a[key], &a[prev]);
	key = prev;
	_QuickSort2(a, 0, key - 1);
	_QuickSort2(a, key + 1, right);
}

 相比最原始的快排更好理解,代码量也少

 快排非递归

void _QuickSort(int* a, int n)
{
	ST st;
	STInit(&st);
	STPush(&st, n-1);
	STPush(&st, 0);
	while (!STEmpty(&st))
	{
		int left = STTop(&st);
		STPop(&st);
		int right = STTop(&st);
		STPop(&st);
		int key = left;
		int prev = left;
		int cur = left + 1;
		while (cur <= right)
		{
			if (a[cur] < a[key] && ++prev != cur)
			{
				swap(&a[prev], &a[cur]);
			}
			cur++;
		}
		swap(&a[key], &a[prev]);
		 key = prev;
		 if ((key+1)<right)
		 {
			 STPush(&st, right);
			 STPush(&st, key + 1);
		 }
		 if (left<(key-1))
		 {
			 STPush(&st, key - 1);
			 STPush(&st, left);
	}
	}
	STDestroy(&st);
}

当递归次数太多时会建立大量函数栈帧,所以在这里实现快排的非递归排序,这里用到了栈的知识 ,模拟了快排的递归过程,类似于二叉树的前序遍历,运用队列也可以实现,但队列是模拟了二叉树的层序遍历,快排的本质还是前序遍历

归并排序:

void _MergeSort(int* a, int left, int right,int*tem)
{
	if (left>= right)
	{
		return;
	}
	int mid = (left + right) / 2;
	int begin1 = left;
	int end1 = mid;
	int begin2 = mid + 1;
	int end2 = right;
	_MergeSort(a, left, mid, tem);
	_MergeSort(a, mid + 1, right, tem);
	int i = begin1;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tem[i++]=a[begin1++];
		}
		else
		{
			tem[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tem[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tem[i++] = a[begin2++];
	}
	memcpy(a + left, tem + left,sizeof(int)*( right - left + 1));
}

 时间复杂度nlogn,具有稳定性

归并排序的非递归 

void _MergeSort1(int* a, int n)
{
	int* tem = (int*)malloc(sizeof(int) * n);
	if (tem == NULL)
	{
		perror("malloc fail");
		return;
	}
	int gap = 1;//gap是每组长度,长度等于n的时候不用归并,理解本质
	while (gap < n)
	{
		for (int i = 0; i <n; i+=2*gap)
		{
			int left = i;
			int right = i + 2 * gap - 1;
			int begin1 = i;
			int end1 = i + gap - 1;
			int begin2 = end1 + 1;
			int end2 = begin2 + gap - 1;
			int j = begin1;
			if (end1 >= n-1 || begin2 >= n)
			{
				break;
			}
			if (end2 >=n)
			{
				end2 = n - 1;
			}
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tem[j++] = a[begin1++];
				}
				else
				{
					tem[j++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				tem[j++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tem[j++] = a[begin2++];
			}
			memcpy(a + left, tem + left, sizeof(int) * (end2 - left + 1));//end2可能会变,这里不能用right减
		}
		gap *= 2;
	}
	free(tem);
	tem = NULL;
}

计数排序

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 = (int*)calloc(sizeof(int),range);
	if (count == NULL)
	{
		return;
	}
	for (int i = 0; i < n; i++)
	{
		count[a[i]-min]++;//出现几次
	}
	int j = 0;
	for (int i = 0; i < range; i++)
	{
		while (count[i]--)
		{
			a[j++] = i + min;
		}
	}
}

时间复杂度o(n+range),空间复杂度 o(range),比较适合处理相对集中的数据,计数排序只能对整数排序,所以这里不讨论其稳定性

 

 

  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值