八大排序(附代码)

直接插入排序

令end=i,记录a[end+1]的值为x。若a[end]>x,则a[end+1]=a[end],end- -;当end减到小于0时,再让a[end+1]=x(如图,将降序成升序)。
在这里插入图片描述

void InsertSort(int* a, int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		int end = i;
		int x = a[end + 1];
		while (end >= 0)
		{
			if (a[end] > x)
			{
				a[end+1] = a[end];
				end--;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = x;
	}
}

希尔排序

基本思想:希尔排序是基于直接插入的,是直接插入排序的优化。直接插入排序是当前数值与后一个数值相比;但再希尔排序中,是当前数值与相隔gap个数值相比,然后让gap不断缩小(一般让gap/=2),直到gap等于1时,就是直接插入排序,在gap==1之前,都是预排序,由于预排序的存在,使得数组的大部分数据不用再交换(即不用走if循环,而直接break),使得直接插入排序优化,这就称为“希尔排序”。
在这里插入图片描述

void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		//gap越大,排的越快,越不接近有序
		//gap越小,拍的越慢,越接近有序
		//最后gap==1,数组已经接近有序,基本不用进if (a[end] > x),直接可以break结束while循环。
		gap /= 2;
		//gap也可以这样
		// gap=gap/3+1

		//直接插入排序的变形,只不过不是int x = a[end + 1];而是int x = a[end + gap];
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int x = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > x)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = x;
		}
	}
	

}

选择排序

基本思想:每一次从待排序的数据元素中选出最小和最大的元素,分别存放在序列的起始位置和末尾位置,然后缩小边界,重复此过程,直到 left>=right,所以元素就排完了。
在这里插入图片描述

//交换函数
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}


//选择排序
void SlectSort(int* a, int n)
{
	int left = 0;
	int right = n - 1;
	while (left < right)
	{
		int small = left;
		int big = left;
		for (int i = left+1; i <= right; i++)
		{
			if (a[small] > a[i])
			{
				small = i;
			}
			if (a[i] > a[big])
			{
				big = i;
			}
		}
		Swap(&a[left], &a[small]);
		if (big == left)// 当最大的数字就是在下标为left的位置上时,由于上一个swap,将最大的数值换到了下标为small的位置上,因此要修正一下big的下标
			big = small;
		Swap(&a[right], &a[big]);
		left++;
		right--;
	}
}

堆排序

基本思想:堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。(这里排升序升序)

  • 先建大堆
    在这里插入图片描述

  • 排序,树顶元素跟最后一个叶子加换,则最大的元素就再序列的末尾位置,这个最大的元素之和就不参与后续的运算,再向下调整建堆,重复此过程,完成排序。
    在这里插入图片描述

//交换函数
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

//向下调整
void AdjustDown(int *a,int parent, int n)
{
	int child = parent * 2 + 1;
	while (child<n)
	{
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child++;
		}
		//不够优化
		//if (a[child] > a[parent])
		//{
		//	Swap(&a[parent], &a[child]);
		//}
		//parent = child;
		//child = parent * 2 + 1;
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}


//向下调整建堆
void CreatHeap(int* a, int n)
{
	//这个parent的下标不对
	//int parent = (n - 1) / 2;
	int parent = (n - 1 - 1) / 2;//最后一个父亲结点
	while (parent >= 0)
	{
		AdjustDown(a,parent,n);
		parent--;
	}
}

//堆排序
void HeapSort(int* a, int n)
{
	CreatHeap(a, n);
	while (n > 0)
	{
		//注意下标是n-1;
		Swap(&a[0], &a[n-1]);
		n--;
		AdjustDown(a, 0, n);
	}

}

冒泡排序

在这里插入图片描述
由此图可得出结论,若有n个数,需要n-1趟排序;第一趟需要对比交换n-1次,第二趟要对比交换n-2次,以此类推。

void BubbleSort(int* a, int n)
{
	int i = 0;
	for (i = 0; i < n - 1; i++)//要排多少趟
	{
		int j = 0;
		int flag = 1;
		for (j = 0; j < n - 1 - i; j++)//每一趟的交换行为
		{
			if (a[j] > a[j + 1])
			{
				Swap(&a[j], &a[j + 1]);
				flag = 0;
			}
		}
		if (flag)//如果flag==1,说明没有交换过,则有序了,就不用再排,break跳出循环
			break;
	}
} 

快速排序

基本思想:再序列中选一个关键值key,让序列中<=key的元素排在key的左边,>=key的元素排在key的右边。为保证key的值不为序列的最小值或最大值,尽可能为序列的中间值,还使用了GetMidIndex函数。

//确保key不是最小或者是最大的数
int GetMidIndex(int* a, int left, int right)
{
	//int mid = (left + right) / 2;
	int mid = left + ((right - left) >> 1);
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
		{
			return mid;
		}
		else if (a[left] > a[right])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
	else // a[left] > a[mid]
	{
		if (a[mid] > a[right])
		{
			return mid;
		}
		else if (a[left] < a[right])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
}




int pation1(int* a, int left, int right)
{
	// 三数取中 -- 面对有序最坏情况,变成选中位数做key,变成最好情况
	int key = GetMidIndex(a, left, right);
	Swap(&a[left], &a[key]);
	key = left;
	while (left < right)
	{
		while (left<right&&a[right] >= a[key])
		{
			right--;
		}
		while (left < right && a[left] <= a[key])
		{
			left++;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[left], &a[key]);
	return left;
}

//快速排序
void QuickSort(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}

	//当区间太小时,还用递归就得不偿失了,可以用直接其他排序让子区间有序,11.18日 1:13:00,有了这个if就可以不用什么那个if
	if (right - left+1 < 10)//right - left + 1为区间个数
	{
		//因为left和right是闭区间,而InsertSort第二个参数是元素个数,所以加1。
		InsertSort(a + left, right - left + 1);
	}
	else
	{
		int key = pation4(a, left, right);
		QuickSort(a, left, key - 1);//递归排关键值左边的数
		QuickSort(a, key + 1, right);//递归排关键值右边的数
	}


}

归并排序

基本思想:将两个有序的数组合并成一个有序的数组。
在这里插入图片描述
那怎么将一个无序的序列,分为两个有序的序列呢?通过不断的递归,使得最终的两个序列只有一个元素,再合并成一个只有2个元素的有序序列;然后通过不断的返回,最终变成两个有序的序列,再合成一个有序的序列。

void _MergeSort(int* a, int left, int right,int* tmp)
{
	if (left >= right)
	{
		return;
	}
	int mid = (left + right) / 2;
	_MergeSort(a, left, mid, tmp);
	_MergeSort(a, mid + 1, right, tmp);

	//自己写的时候不知道怎么把两个数组归并到tmp中,即不知道怎么控制tmp的下标
	//int i = left;
	//int j = mid + 1;
	//while (i <= mid && j <= right)
	//{
	//	if (a[i] > a[j])
	//	{
	//		tmp[] = a[i];
	//		i++;

	//	}
	//	else
	//	{
	//		tmp[] = a[j];
	//		j++;
	//	}
	//}

	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;
	int i = left;
	while(begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}
	for (int j = left; j <= right; j++)
	{
		a[j] = tmp[j];
	}



}

//归并排序
void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	_MergeSort(a, 0, n - 1, tmp);
	free(tmp);
	tmp = NULL;
	
}

计数排序

基本思想:开一个数组a,当有n个x,就让下标为x的值为n,然后检索新开的数组排序。
在这里插入图片描述

//计数排序
void CountSort(int* a, int n)
{
	int small = a[0];
	int big = a[0];
	for (int i = 0; i < n; i++)
	{
		if (a[i] < small)
		{
			//不是small=i;
			small = a[i];
		}
		if (a[i] > big)
		{
			//不是big=i;
			big = a[i];
		}
	}
	//注意要加1
	int range = big - small+1;//当序列是1000-1100的数时,那么a[1000]之前就没有元素,我们不必开这么多的空间,我们就只要开(big - small+1)个空间(即range),例如1000有3个,tmp[0]为3,最终排序的时候tmp+1000来排序
	int* tmp = (int*)malloc(sizeof(int) * range);
	memset(tmp, 0, sizeof(int) * range);
	for (int i = 0; i < n; i++)
	{
		//不是a[i]-range;
		tmp[a[i]-small]++;
	}
	int j = 0;
	for (int i = 0; i < range; i++)
	{
		while (tmp[i]--)
		{
			//不是i+range
			a[j++] = i + small;
		}
	}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值