排序的几种类型

本文深入探讨了选择排序、冒泡排序、插入排序、快速排序、堆排序等经典排序算法的设计思想、实现过程及排序效果,通过实例展示了不同算法在处理数据集时的性能差异,并对比了它们在实际应用中的适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//快速排序

//排序思想

//1.从数列中挑出一个元素,称为 “基准”(pivot),

//2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。

//3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序

wKiom1c6z2ODq26tAAFrWtvqt58860.gif

int PartSort(int* a, int left, int right)
{
	int key = a[right];//找最右边一个为基准
	int begin = left;
	int end = right - 1;
	while (begin < end)
	{
		while (begin < end&&a[begin] <= key)//当找到大于基准数时停
		{
			++begin;
		}
		while (begin < end&&a[end] >= key)//当找到小于基准数时停
		{
			--end;
		}
		if (begin < end)
		{
			swap(a[begin], a[end]);
		}
	}
	if (a[begin]>a[right])
	{
		swap(a[begin], a[right]);
		return begin;
	}
	else
	{
		return right;
	}
}
void QuickSort(int* a, int left, int right)  //快排
{
	assert(a);
	if (left >= right)
		return;
	int div = PartSort(a, left, right);   
	QuickSort(a, left, div - 1);
	QuickSort(a, div+1, right);
}

堆排序

//堆排序
void AdjustDown(int* a, size_t size, size_t parent)
{
	size_t child = parent * 2 + 1;
	while (child < size)
	{
		if (child + 1 < size&&a[child]< a[child + 1])
		{
			++child;
		}
		if (a[child] > a[parent])
		{
			swap(a[child], a[parent]);
			parent= child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapSort(int*a ,size_t size)
{
	assert(a);
	for (int i = (size - 2) / 2; i >= 0; --i)  //建堆
	{
		AdjustDown(a, size, i);
	}
	for (size_t i = 0; i < size; ++i)
	{
		swap(a[0], a[size - i - 1]);
		AdjustDown(a, size - i - 1, 0);
	}
}

排序效果:

wKioL1c60H7TdI_sAARJvLiNWU4473.gif

选择排序:

设计思想:

//选择排序(Selection sort)是一种简单直观的排序算法。

//它的工作原理如下。首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。

//以此类推,直到所有元素均排序完毕。

void SelectSort(int* a, size_t size)   //选择排序
{
	assert(a);
	for (size_t i = 0; i < size-1; i++)
	{
		int min = i;
		//查找最小值
		for (size_t j = i+1; j < size; j++)
		{
			if (a[min]>a[j])
			{
				min = j;
			}
		}
		//交换
		if (min!=i)
		{
			swap(a[min], a[i]);
		}
	}
}

排序效果:

wKioL1c60I2AHbuyAAA0SbQuz3M741.gif

//冒泡排序

//排序思想:

//1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。

//2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

//3、针对所有的元素重复以上的步骤,除了最后一个。

//4、每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

//void BubbleSort(int* a,size_t size)
//{
//	for (size_t i = 0; i < size-1; ++i)
//	{
//		for (size_t j = i + 1; j < size; ++j)
//		{
//			if (a[i]>a[j])
//			{
//				swap(a[i], a[j]);
//			}
//		}
//	}
//}
//改进
void bubbleSort1(int* a, int size)
{
	int j = 0;
	while (size > 0)
	{
		for (j = 0; j < size - 1; j++)
		{
			if (a[j] > a[j + 1])
			{
				swap(a[j], a[j + 1]);
			}
		}
		size--;
	}
}

插入排序:

设计思想:

1.从第一个元素开始,该元素可以认为已经被排序

2.取出下一个元素,在已经排序的元素序列中从后向前扫描

3.如果该元素(已排序)大于新元素,将该元素移到下一位置

4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置

5.将新元素插入到该位置中

6.重复步骤2

void InsertSort(int *a, int size)    //插入排序
{
	assert(a);
	for (int i = 1; i < size; i++)
	{
		int cur = i;
		int next = a[i];
		while (i >=0 && a[cur-1] > next)
		{
			a[cur] = a[cur-1];
			--cur;
		}
		a[cur] = next;
	}
}

希尔排序,也称递减增量排序算法,是插入排序的一种高速而稳定的改进版本。

该方法的基本思想是:

先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。

因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的.

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

1、插入排序在对几乎已经排好序的数据操作时,效率高, 即可以达到线性排序的效率

2、但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位>

void ShellSort(int* a,size_t size)
{
	int gap = size;
	while (gap > 1)
	{
		gap = gap / 3 + 1;
		for (size_t i = 0; i < size - gap; i++)
		{
			int end=i;
			int tmp = a[end + gap];
			while (end >= 0 && a[end] > tmp)
			{
				swap(a[end + gap], a[end]);
				end -= gap;
			}
			a[end + gap] = tmp;
		}
	}
}

排序效果:

wKiom1c6z7nyhkxqAAuT3ewzFDs482.gif


本文出自 “土豆_” 博客,请务必保留此出处http://10738432.blog.51cto.com/10728432/1774380

### 排序算法的分类 排序算法可以根据不同的标准进行分类,主要包括内部排序与外部排序、比较型排序与非比较型排序等类别。 #### 内部排序与外部排序 当所有数据记录都可以一次性加载到内存中进行排序时,这类排序被称为**内部排序**。常见的内部排序算法包括插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序和基数排序等[^2]。 如果数据量过大,无法一次性全部加载到内存,则需要采用**外部排序**方法。这种情况下,排序过程中会涉及对外存(如磁盘)的读写操作,以处理超出内存容量的数据集[^2]。 #### 比较型排序与非比较型排序 **比较型排序**依赖于元素之间的两两比较来决定它们的顺序。典型的比较型排序有冒泡排序、快速排序、归并排序以及堆排序等。这些算法的时间复杂度下限为 O(n log n)。 **非比较型排序**则不依赖于元素间的直接比较,而是利用了数据的一些特定结构特性来进行排序,例如计数排序、桶排序和基数排序等。其中,基数排序是一种高效的非比较型排序算法,最初设计用于整数排序,但现在已经扩展至字符串和其他类型数据的排序[^1]。 #### 稳定性分类 根据排序后相同键值记录的相对顺序是否保持不变,排序算法还可以分为稳定排序和不稳定排序。例如,冒泡排序和归并排序是稳定的,而快速排序和堆排序则是不稳定的。 #### 时间复杂度分类 按照时间复杂度的不同,排序算法可以进一步细分为: - **线性对数时间**:如快速排序、归并排序和堆排序。 - **平方时间**:如插入排序、选择排序和冒泡排序。 - **线性时间**:如计数排序、桶排序和基数排序,在特定条件下能达到线性时间复杂度。 ```python def bubble_sort(arr): n = len(arr) # 遍历所有数组元素 for i in range(n): # 最后i个元素已到位,所以内层循环减i for j in range(0, n-i-1): # 如果当前元素大于下一个元素,则交换它们 if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] ``` ```python def quick_sort(arr, low, high): if low < high: pi = partition(arr, low, high) quick_sort(arr, low, pi - 1) quick_sort(arr, pi + 1, high) def partition(arr, low, high): pivot = arr[high] # 选取最后一个元素作为基准 i = low - 1 # 小于基准的区域边界 for j in range(low, high): if arr[j] <= pivot: i += 1 arr[i], arr[j] = arr[j], arr[i] arr[i + 1], arr[high] = arr[high], arr[i + 1] return i + 1 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值