排序

一、插入排序

1、直接插入排序

void InsertSort(int arr[], int size)
{
	if (arr == NULL || size <= 0)
		return;

	for (int i =0; i < size-1; i++)
	{
		int end = i;//一个有序序列的结尾
		int tmp = arr[i+1];
		while (end >= 0 && arr[end]>tmp)
		{
			arr[end + 1] = arr[end];
			end--;
		}
		arr[end + 1] = tmp;
	}
}

有序或接近有序的情况下非常快

2、希尔排序

其实是插入排序的优化,在直接插入排序在有序或接近有序的时候是最快的

void ShellSort(int arr[], int size)
{
	if (arr == NULL || size <= 0)
		return;
	int gap = size;

	while (gap > 1)
	{
		gap = gap / 3 + 1;//保证当gap《3时,gap的值转换为1
		for (int i = 0; i < size - gap; ++i)
		{
			int end = i;
			int tmp = arr[end + gap];
			while (end >= 0 && arr[end]>tmp)//几个不同的区间同时控制,而不是控制完一个区间,再控制下一个区间
			{
				arr[end + gap] = arr[end];
				end -= gap;
			}
			arr[end + gap] = tmp;
		}
	}
}
前面几次的gap都是预排序,只是为了最后一次gap==1时候的排序

效果最好:正好是逆序

效果最坏:本身就接近有序的情况(比直接插入排序要坏)

二、选择排序

1、.选择排序

选择排序其实是一个比较鸡肋的排序,最好和最坏的情况下时间复杂度都是O(N^2)(n+(n-1)+(n-2)+...+1)

(1)未优化

void SelectSort(int* arr, int size)
{
	if (arr == NULL&&size <= 0)
		return;

	for (int i = 0; i < size; i++)
	{
		int minIndex = i;
		for (int j = i + 1; j < size; j++)
		{
			if (arr[j] < arr[minIndex])
				minIndex = j;
		}
		std::swap(arr[minIndex], arr[i]);
	}

}
(2)优化:每一趟都可以选出最大值和最小值,然后进行交换

void SelectSort_OP(int* arr, int size)
{
	if (arr == NULL || size <= 0)
		return;
	int left = 0;
	int right = size - 1;
	while (left < right)
	{
		for (int i = left; i <= right; i++)
		{
			if (arr[i] < arr[left])
			{
				std::swap(arr[i], arr[left]);
			}
			if (arr[i] > arr[right])
			{
				std::swap(arr[i], arr[right]);
			}
		}
		left++;
		right--;
	}
}

2、堆排序

void AdjustDown(int arr[],int size, int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		if ((child + 1 < size)&&(arr[child + 1] > arr[child]))
		{
			child++;
		}

		if (arr[child]>arr[parent])
		{
			std::swap(arr[child], arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}


void HeapSort(int* arr, int size)
{
	if (arr == NULL || size <= 0)
		return;

	for (int i =  (size - 2) / 2;i>=0; i--)//从后向前建堆
	{
		AdjustDown(arr, size, i);
	}

	for (int i = 0; i < size; i++)
	{
		std::swap(arr[0], arr[size-1-i]);//最后一个位置的下标
		AdjustDown(arr, size - 1 - i, 0);//数据的个数,注意这里是size-1-i,因为已经发生了一次交换
	}
}


三、交换排序

1.冒泡排序

(1)未优化

void BubbleSort(int arr[], int size)
{
	if (arr == NULL || size <= 0)
		return;
	for (int i = 0; i < size - 1; i++)
	{
		for (int j = 0; j < size - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
				std::swap(arr[j], arr[j + 1]);
		}
	}

}

(2)优化一:设置标志位,判断是否发生交换

void BubbleSort_OP1(int arr[], int size)
{
	if (arr == NULL || size <= 0)
		return;

	for (int i = 0; i < size - 1; i++)
	{
		int flag = -1;
		for (int j = 0; j < size - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				std::swap(arr[j], arr[j + 1]);
				flag = j;
			}
		}
		if (flag == -1)
			break;
	}
}

(2)优化二:记录最后一次发生交换的位置

void BubbleSort_OP2(int arr[], int size)
{
	if (arr == NULL || size <= 0)
		return;

	int lastSwapPos = size - 1;//最后一个发生交换的位置,下面由这句话控制i < end,<span style="color:#ff0000;">也可以记忆为大于lastSwapPos的坐标的值都是有序的</span>
	while (lastSwapPos > 0)
	{
		int end = lastSwapPos;
		for (int i = 0; i < end; i++)//注意这里是<不是<=,因为下面是arr[i]和arr[i+1]比较
		{
			if (arr[i] > arr[i + 1])
			{
				lastSwapPos = i;
				std::swap(arr[i], arr[i + 1]);
			}
		}
		if (lastSwapPos == end)
		{
			break;
		}
	}
}

(3)优化三:

其实是第二种方法的一种优化,遍历两次,从左往右遍历,记录最后一个上浮的位置right,该坐标以上的位置都是有序的;从右往左遍历,记录最后一个下沉的位置left,

下一次直接在[left,right]这个区间中遍历即可

void BubbleSort_OP3(int arr[], int size)
{
	if (arr == NULL || size <= 0)
		return;

	int left = 0;
	int right = size - 1;
	
	while (left < right)
	{
		int lastSwapPos = right;

		for (int i = 0; i < lastSwapPos; i++)
		{
			if (arr[i] > arr[i + 1])
			{
				right = i;
				std::swap(arr[i], arr[i + 1]);
			}
		}
		if (lastSwapPos == right)
			break;

		lastSwapPos = left;
		for (int i = right; i > lastSwapPos; i--)
		{
			if (arr[i] < arr[i - 1])
			{
				left = i;
				std::swap(arr[i], arr[i - 1]);
			}
		}
		if (lastSwapPos == left)
			break;
	}
}

2、快速排序

有序写法比较多所以单独写为一篇博客








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值