常见的几种排序算法

目录

一、插入排序

1、直接插入排序

1.1、排序方法

1.2、图解分析

1.3、代码实现

2、希尔排序

2.1、排序方法

2.2、图解分析

2.3、代码实现

二、选择排序

1、直接选择排序

1.1、排序方法

1.2、图解分析

1.3、代码实现

2、堆排序

2.1、排序方法

2.2、图解分析

2.3、代码实现

三、交换排序

1、冒泡排序

1.1、排序方法

1.2、图解分析

1.3、代码实现

2、快速排序

2.1、hoare排序

2.1.1、图解分析

2.1.2、代码实现

2.2、挖坑法

2.2.1、图解分析

2.2.2、代码实现

2.3、前后指针法

2.3.1、图解分析

2.3.2、代码实现

四、归并排序

1、排序方法

2、图解分析

3、代码实现


一、插入排序

基本思想:把待排序的数据按其关键码值的大小追个插入到一个有序序列中,得到一个新的有序序列。

1、直接插入排序

1.1、排序方法

当插入第i个元素时,数组的前i-1个元素已经有序,将第i个元素与前i-1个元素的关键码值进行比较,找到合适的位置插入,并将该位置之后的所有元素顺序后移即可。

1.2、图解分析

1.3、代码实现

cpp 复制代码
// 直接插入排序
void InsertSort(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		int tmp = a[i];
		int end = i-1;
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;;
	}
}

2、希尔排序

2.1、排序方法

希尔排序是对直接插入排序的优化。希尔排序的基本思想是:先选定一个合理的增量gap,把待排序文件中的数据分成gap个组,每一组中的相邻元素位置相差gap的距离,对每组元素各自进行直接插入排序。然后适当缩小gap,重复上述操作。直到gap等于1时,所有元素在同一组内最后一次直接插入排序。

2.2、图解分析

2.3、代码实现

cpp 复制代码
// 希尔排序
void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		bool change = false;
		gap = gap / 3 + 1;
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end-=gap;
					change = true; 
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;;
		}
		if (change == false)
		{
			break;
		}
	}
}

二、选择排序

基本思想:每次从待排序元素中选出最大(或最小)的一个元素将其存放在已有序序列的后一个位置,重复操作直到所有元素存放结束得到一个有序的新序列。

1、直接选择排序

1.1、排序方法

在元素集合arr[i]~arr[n-1]中选出关键码值最大(小)的元素,若该元素不是第一个(或最后一个),则将其与这组元素中的第一个(或最后一个)元素进行交换,对剩余未排序元素重复上述操作直到结束。

1.2、图解分析

1.3、代码实现

cpp 复制代码
// 选择排序
void SelectSort(int* a, int n)
{
	
	int begin_i = 0;
	int end_i = n-1;
	while (begin_i < end_i)
	{
		int max_i = end_i;
		int min_i = begin_i;
		for (int i = begin_i; i <= end_i; i++)
		{
			if (a[i] < a[min_i])
			{
				Swap(&a[i], &a[min_i]);
			}
			if (a[i] > a[max_i])
			{
				Swap(&a[i], &a[max_i]);
			}
		}
		begin_i++;
		end_i--;
	}
}

2、堆排序

2.1、排序方法

堆排序的操作对象是堆,排序会调整部分节点在堆中的相对位置,为了不破坏堆的性质,我们将堆顶节点与堆的最后一个节点交换,再将除最后一个节点之外的其他节点通过向下调整算法调整成为一个新的堆。重复操作直到只剩下一个节点为止。

2.2、图解分析

2.3、代码实现

cpp 复制代码
//堆排序

typedef struct Heap
{
	int* a;
	int size;
	int capacity;
}Heap;

//向下调整算法
void AdjustDwon(int* a, int n, Heap* hp)
{
	for (int parent = (n - 2) / 2; parent >= 0; parent--)
	{
		int child = parent * 2 + 1;
		while (child < n)
		{
			bool change = false;
			if (child + 1 < n)
			{
				child = hp->a[child] > hp->a[child + 1] ? child : child + 1;
			}
			if (hp->a[child] > hp->a[parent])
			{
				int tmp = hp->a[parent];
				hp->a[parent] = hp->a[child];
				hp->a[child] = tmp;
				change = true;
				parent = child;
				child = parent * 2 + 1;
			}
			if (change == false)
			{
				break;
			}
		}
	}
}

//初始化堆
void InitialHeap(Heap* hp,int n)
{
	if (!hp)
	{
		return;
	}
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (!tmp)
	{
		perror("InitialHeap::malloc:");
		return;
	}
	hp->a = tmp;
	hp->size = 0;
	hp->capacity = n;
}

//创建堆
void HeapBuild(Heap* hp, int* a, int n)
{
	assert(hp);
	for (int i = 0; i < n; i++)
	{
		hp->a[i] = a[i];
	}
	AdjustDwon(a, n, hp);
}

//排序
void Sort(Heap* hp, int* a, int n)
{
	int end = n - 1;
	while (end > 0)
	{
		int tmp = hp->a[0];
		hp->a[0] = hp->a[end];
		hp->a[end] = tmp;
		a[end] = hp->a[end];
		end--;
		AdjustDwon(a, end, hp);
	}
	a[0] = hp->a[0];
}

三、交换排序

基本思想:根据序列中两个元素的关键码值的大小来判断是否需要交换他们在序列中的位置,默认将关键码值较大的元素向序列的尾部移动,关键码值较小的元素向序列的首部移动。

1、冒泡排序

1.1、排序方法

冒泡排序是将待排序元素的关键码值最大(小)的元素通过从前往后依次两两比较交换到最后面的位置。每操作一次可以确定一个元素在有序序列中的的位置。

1.2、图解分析

1.3、代码实现

cpp 复制代码
// 冒泡排序
void BubbleSort(int* a, int n)
{
	for (int j = 1; j < n; j++)
	{
		for (int i = 0; i < n - j; i++)
		{
			if (a[i] > a[i + 1])
			{
				int tmp = a[i];
				a[i] = a[i + 1];
				a[i + 1] = tmp;
			}
		}
	}
}

2、快速排序

基本思想:快速排序是任取待排序元素序列中的某元素的关键码值作为基准值,按照该基准值将待排序集合分割成左右两个子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,再对左右子序列重复该过程直到结束。

2.1、hoare排序

2.1.1、图解分析

key选左边,从右边出发。保证了相遇位置的值比key位置的值小;

key选右边,从左边出发。保证了相遇位置的值比key位置的值大;

(注意:key指的是下标)

2.1.2、代码实现

cpp 复制代码
// 快速排序hoare版本
int PartSort1(int* a, int left, int right)
{
	int key = left;
	while (left < right)
	{
		while (left < right && a[right] >= a[key])
		{
			right--;
		}
		while (left<right && a[left]<=a[key])
		{
			left++;
		}
		int tmp = a[right];
		a[right] = a[left];
		a[left] = tmp;
	}
	int tmp = a[key];
	a[key] = a[left];
	a[left] = tmp;
	return left;
}

2.2、挖坑法

2.2.1、图解分析

( 注意: 这里的key是一个变量,不是下标)

2.2.2、代码实现

cpp 复制代码
// 快速排序挖坑法
int PartSort2(int* a, int left, int right)
{
	int key = a[left];
	int hole = left;
	while (left < right)
	{
		while (hole < right)
		{
			if (a[right] < key)
			{
				a[hole] = a[right];
				hole = right;
				break;
			}
			right--;
		}
		while (hole > left)
		{
			if (a[left] > key)
			{
				a[hole] = a[left];
				hole = left;
				break;
			}
			left++;
		}
	}
	a[hole] = key;
	return hole;
}

2.3、前后指针法

2.3.1、图解分析

(这里的key同样是一个变量,不是下标)

2.3.2、代码实现

cpp 复制代码
// 快速排序前后指针法
int PartSort3(int* a, int left, int right)
{
	int prev = left;
	int cur = prev + 1;
	int key = a[left];
	while (cur <= right)
	{
		if (a[cur] < key)
		{
			prev++;
			int tmp = a[prev];
			a[prev] = a[cur];
			a[cur] = tmp;
		}
		cur++;
	}
	a[left] = a[prev];
	a[prev] = key;
	return prev;
}

四、归并排序

1、排序方法

归并排序是建立在归并操作上的一种排序算法。归并排序是将已有序的子序列合并,得到完全有序的序列;即先使每个字序列有序,再使子序列段间有序。归并排序的核心思想是先分解后合并。

2、图解分析

3、代码实现

cpp 复制代码
// 归并排序递归实现

void _MergeSort(int* a, int begin, int end, int* tmp)
{
	if (begin >= end)
	{
		return;
	}
	int mid = (begin + end) / 2;
	_MergeSort(a, begin, mid, tmp);
	_MergeSort(a, mid + 1, end, tmp);
	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	int i = begin;
	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++];
	}
	memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}

void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("MergeSort-->malloc:");
		return;
	}
	_MergeSort(a, 0, n - 1, tmp);
	free(tmp);
	tmp = NULL;
}
相关推荐
蓑 羽4 分钟前
力扣438 找到字符串中所有字母异位词 Java版本
java·算法·leetcode
源代码:趴菜7 分钟前
LeetCode63:不同路径II
算法·leetcode·职场和发展
Reese_Cool12 分钟前
【C语言二级考试】循环结构设计
android·java·c语言·开发语言
儿创社ErChaungClub22 分钟前
解锁编程新境界:GitHub Copilot 让效率翻倍
人工智能·算法
前端西瓜哥26 分钟前
贝塞尔曲线算法:求贝塞尔曲线和直线的交点
前端·算法
zxctsclrjjjcph29 分钟前
【C语言】常见的C语言概念
c语言·开发语言
小灰灰爱代码34 分钟前
C++——求3个数中最大的数(分别考虑整数、双精度数、长整数的情况),用函数模板来实现。
开发语言·c++·算法
南加第一划水37 分钟前
Leetcode 每日一题:Evaluate Division
算法·leetcode·职场和发展
m0_714590261 小时前
汇编(实现C语言程序的调用)
c语言·开发语言·汇编
逝去的秋风1 小时前
【代码随想录训练营第42期 Day61打卡 - 图论Part11 - Floyd 算法与A * 算法
算法·图论·floyd 算法·a -star算法