数据结构之排序

1.排序的概念及常见的排序算法

   1.1排序的概念

  • 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
  • 稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
  • 内部排序:数据元素全部放在内存中的排序。
  • 外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

   1.2常见排序算法

2.常见排序算法的实现

 2.1直接插入排序

  2.1.1基本思想

          直接插入排序是一种简单的插入排序法,其基本思想是:把待排序的记录按其关键码值的        大 小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有      序序列。

2.1.2代码实现

​
void InsertSort(int* a, int n) {
	//[0,end]的区间有序 把end+1的数向前插入
	for (int i = 0; i < n - 1; i++) {
		int end = i;
		int tmp = a[end + 1];
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + 1] = a[end];
				end--;
			}
			else {
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

​

2.2希尔排序

2.2.1基本思想

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

2.2.2代码实现

void ShellSort(int* a, int n) {
	//希尔分为预排序和插入排序,预排序是分组写
	int gap = n;
	while (gap > 1)
	{
		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;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

2.3选择排序

2.3.1基本思想

在元素集合array[i]--array[n-1]中选择关键码最大(小)的数据元素若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换在剩余的array[i]--array[n-2](array[i+1]--array[n-1])集合中,重复上述步骤,直到集合剩余1个元素。

2.3.2代码实现

        这里的代码是对选择排序的优化版本,它可以同时选出最大值和最小值。

//选择排序
void SelectSort(int* a, int n) {
	//遍历选出最小的和最大的数的下标,再进行交换最小的换到最左边,最大的换到最右边
	int begin = 0,end=n-1;
	
	while (begin < end)
	{
		int min = begin, max = begin;//每次循环后缩小区间
		for (int i = begin + 1; i <= end; i++)
		{
			if (a[i] < a[min])
			{
				min = i;
			}
			if (a[i] > a[max])
			{
				max = i;
			}
		}
		//swap(&a[begin], &a[min]);
		防止最大的下标和开始一样,最小的和end一样,导致重复两次置换数组元素
		//if (max == begin)
		//{
		//	max = min;
		//}
		//swap(&a[end], &a[max]);
		swap(&a[end], &a[max]);
		if (min == end)
		{
			min = max;
		}
		swap(&a[begin], &a[min]);
		begin++;
		end--;	
	}
	Print(a, n);
}

2.4堆排序

2.4.1基本思想

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

2.4.2代码实现

//堆排序

void AdjustDown(HPDataType* a, int parent,int n) {

	int child = parent * 2 + 1;
	while (child<n)
	{
		//选出左右孩子里小的那个,child+1要小于n,因为可能只有一个孩子
		if ((child+1)<n && a[child+1] < a[child])
		{
			child++;
		}
		if (a[child] < a[parent])
		{
			swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapSort(int* a, int n) {
	//升序建大堆,降序建小堆
	int i = 0;
	for (i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, i, n);
	}
	int end = n - 1;//end记录最后一个节点的下标,把第一个节点和最后一个节点换位置然后向下调整
	while (end>0)
	{
		swap(&a[0], &a[end]);
		AdjustDown(a, 0, end);
		end--;
	}
}

2.5冒泡排序

2.5.1基本思想      

 冒泡排序是在数组中对相邻两个元素进行对比,依次循环知道所有数据有序。属于最简单的排序算法之一。

2.5.2代码实现

//冒泡排序
void BubbleSort(int* a, int n) {
	for (int j = 0; j < n; j++)
	{
		for (int i = 0; i < n-j-1; i++)
		{
			if (a[i] > a[i + 1])
			{
				swap(&a[i], &a[i + 1]);
			}
		}
	}
	Print(a, n);
}

2.6快速排序

2.6.1基本思想

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

2.6.2Hoare版本的快速排序

//经典快排
void PartSort1(int* a, int left, int right) {
	int begin, end;
	begin = left,  end = right;
	if (left >= right)
		return;//返回条件
	int keyi = left;
	while (left < right)
	{
		while(left<right&&a[right] >= a[keyi])//R找小,R必须先走,必须要有left<right的判断条件要不right和left相遇无法判断
		{
			right--;
		}
		while(left<right&&a[left] <= a[keyi])//L找大
		{
			left++;
		}
		swap(&a[left], &a[right]);
	}
	swap(&a[left], &a[keyi]);
	keyi = left;
	// [begin,keyi]keyi[keyi+1,end]
	PartSort1(a, begin, keyi);
	PartSort1(a, keyi + 1, end);
}

2.6.3双指针法快速排序

void PartSort3(int* a, int left, int right) {
	int prev = left,cur=left+1;
	if (left >= right)
		return;
	int keyi = left;
	while (cur < right +1)
	{
		if (a[cur]<a[keyi])
		{
			prev++;
			swap(&a[prev], &a[cur]);
		}
		cur++;
	}
	swap(&a[prev], &a[keyi]);
	keyi = prev;
	//[left,keyi]
	PartSort3(a, left, keyi);
	PartSort3(a, keyi+1, right);
}

2.6.4非递归版快速排序

借用数据结构栈来进行堆递归时栈帧的模拟,每一次把区间的端点值入到栈中,先入右端点再入左端点,出栈的时候先出左端点再出右端点。之后再以keyi为界限把区间再度二分。依次循环直到栈为空。

void QuickSortNonR(int* a, int left, int right) {
	//栈中存放区间端点,先入右端点后入左端点。
	Stack st;
	StackInit(&st);
	StackPush(&st, right);
	StackPush(&st, left);
	while (!StackEmpty(&st))
	{
		int begin=StackTop(&st);
		StackPop(&st);
		int end = StackTop(&st);
		StackPop(&st);
		int cur = begin + 1, prev = begin, keyi = begin;
		while (cur <=end)
		{
			if (a[cur] < a[keyi])
			{
				prev++;
				swap(&a[prev], &a[cur]);
			}
			cur++;
		}
		swap(&a[prev], &a[keyi]);
		keyi = prev;
		//[begin,keyi]keyi[keyi+1,end]
		if (keyi + 1 < end)
		{
			StackPush(&st, end);
			StackPush(&st, keyi + 1);
		}
		if (keyi > begin)
		{
			StackPush(&st, keyi);
			StackPush(&st, begin);
		}
	}
	
	StackDestroy(&st);
}

2.7归并排序

2.7.1基本思想

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。


2.7.2代码实现

void _MergeSort(int* a, int begin, int end, int* tmp)
{
	if (begin == end)
		return;

	int mid = (begin + end) / 2;
	// [begin, mid] [mid+1, end]
	_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;
	// 依次比较,取小的尾插tmp数组
	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));
}

相关推荐

  1. 数据结构内部排序

    2024-03-30 22:10:02       32 阅读
  2. 数据结构快速排序

    2024-03-30 22:10:02       33 阅读
  3. 数据结构基数排序

    2024-03-30 22:10:02       35 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-30 22:10:02       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-30 22:10:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-30 22:10:02       20 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-30 22:10:02       20 阅读

热门阅读

  1. 数据可视化之极坐标

    2024-03-30 22:10:02       17 阅读
  2. 安卓APP开发中的重要环节:数据和文件存储概述

    2024-03-30 22:10:02       20 阅读
  3. Golang- 邮件服务,发送邮件

    2024-03-30 22:10:02       21 阅读
  4. 【Docker】常用命令 docker compose

    2024-03-30 22:10:02       16 阅读
  5. C语言- %i 读取不同进制的数

    2024-03-30 22:10:02       14 阅读
  6. 2023春秋杯冬季赛wp

    2024-03-30 22:10:02       21 阅读
  7. uniapp 未配置appkey或配置错误的解决

    2024-03-30 22:10:02       16 阅读
  8. Doris案例篇—Doris 在思必驰的应用实践

    2024-03-30 22:10:02       19 阅读
  9. kubelet源码阅读

    2024-03-30 22:10:02       20 阅读
  10. 【软考---系统结构设计师】IPv6

    2024-03-30 22:10:02       21 阅读