数据结构(C语言版)-7. 排序

排序的基本概念

在这里插入图片描述

插入排序

在这里插入图片描述

直接插入排序

void D_Insert(RecordType R[], int n)
{	
	// 愚蠢的做法:
	// 不需要每次将fast的元素和已经排好序的序列从0开始
	// 比较,只需要将其和最大的元素进行比较
	/*int slow = 0, fast = 1;
	for(fast=1;fast<n;fast++)
	{
		for (int i = 0; i <= slow; i++)
		{
			if (R[i].key >= R[fast].key)
			{
				int Icur = i;
				RecordType Rcur = R[fast];
				for (i = fast; i > Icur; i--)
					R[i] = R[i - 1];
				R[Icur] = Rcur;
			}
		}
		slow++;
	}*/
	for (int i = 1; i < n; i++)
	{
		if (R[i].key < R[i - 1].key)
		{// 需要将R[i]插入到有序序列R[0]~R[i-1]中
			RecordType cur = R[i];
			int  j;
			for(j = i-1;j>=0;j--)
			{
				R[j + 1] = R[j];
				if (cur.key > R[j].key)
					break;
			}
			if (j < 0)
				R[0] = cur;
			else
				R[j] = cur;
		}
	}
	
}
  • 设置监视哨
    在这里插入图片描述

折半插入排序

在这里插入图片描述

// 折半插入排序
void B_Insert(RecordType R[], int n)
{

	for (int i = 1; i < n; i++)
	{
		if (R[i].key < R[i - 1].key)
		{// 需要将R[i]插入到有序序列R[0]~R[i-1]中
			RecordType cur = R[i];
			int  low = 0, high = i - 1;
			// 寻找插入位置
			while (low < high)
			{
				int mid = (low + high) / 2;
				if (R[mid].key > cur.key)
					high = mid - 1;
				else
					low = mid + 1;
			}
			// high+1为插入位置
			for (int j = i - 1; j >= high + 1; j--)
				R[j + 1] = R[j];
			R[high + 1] = cur;
		}
	}

}

希尔排序

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

交换排序

在这里插入图片描述

冒泡排序

// 交换排序
void BubbleSort(RecordType R[], int m)
{
	int swap = 0;
	for (int i = 0; i < m; i++)
	{
		swap = 0;
		for (int j = 0; j < m - i - 1; j++)
		{
			if (R[j].key > R[j + 1].key)
			{
				swap = 1;
				RecordType tmp = R[j];
				R[j] = R[j + 1];
				R[j + 1] = tmp;
			}
		}
		if (!swap)
			break;
	}
}

双向冒泡排序

在这里插入图片描述

在这里插入图片描述

void DBubbleSort(RecordType R[], int m)
{
	int swap = 0;
	for (int i = 0; i < m; i++)
	{
		// 从左到右排序
		swap = 0;
		for (int j = 0; j < m - i - 1; j++)
		{
			if (R[j].key > R[j + 1].key)
			{
				swap = 1;
				RecordType tmp = R[j];
				R[j] = R[j + 1];
				R[j + 1] = tmp;
			}
		}
		if (!swap)
			break;
		// 从右到左排序
		swap = 0;
		for (int j = m-1; j >i; j--)
		{
			if (R[j].key < R[j - 1].key)
			{
				swap = 1;
				RecordType tmp = R[j];
				R[j] = R[j - 1];
				R[j - 1] = tmp;
			}
		}
		if (!swap)
			break;
	}
}

快速排序

在这里插入图片描述


int Partition(RecordType R[], int i, int j) // 划分算法
{
	// 对R[i]-R[j],以R[i]为基准记录进行划分,并返回R[i]在划分后的放置位置
	int left = i ;
	int right = j-1;
	RecordType par = R[i];
	while (left < right)
	{
		// 先在右边找到小于par的元素
		while (left < right && R[right].key >= par.key)
			right--;
		if(left < right)
			R[left++] = R[right];
		//在左边找到大于par的元素
		while (left < right && R[left].key <= par.key)
			left++;
		if (left < right)
			R[right--] = R[left];
	}
	R[left] = par;
	return left;
}
void QuickSort(RecordType R[], int s, int t) // 快速排序
{
	int i;
	if (s < t)
	{
		i = Partition(R, s, t);
		QuickSort(R, s, i); // 注意以后所有的算法按照STL的标准区间都是左闭右开
		QuickSort(R, i+1, t);
	}
}

在这里插入图片描述
在这里插入图片描述

选择排序

在这里插入图片描述

直接选择排序

void SelectSort(RecordType R[], int n)
{
	int Imin;
	for (int j =0; j < n; j++)
	{
		Imin = j;
		// 找出最小的元素
		for (int i = j; i < n ; i++)
		{
			if (R[Imin].key > R[i].key)
				Imin = i;
		}
		// 将最小元素依次放在前面
		RecordType tmp = R[Imin];
		R[Imin] = R[j];
		R[j] = tmp;
	}

}

双向直接选择排序

void DSelectSort(RecordType R[], int n)
{
	int Imin,Imax;
	for (int j = 0; j < n; j++)
	{
		Imin = j;
		// 找出最小的元素
		for (int i = j; i < n; i++)
		{
			if (R[Imin].key > R[i].key)
				Imin = i;
		}
		// 将最小元素依次放在前面
		RecordType tmp = R[Imin];
		R[Imin] = R[j];
		R[j] = tmp;



		Imax = n - 1 - j;
		// 找出最大的元素
		for (int i = n-1-j; i > j; i--)
		{
			if (R[Imax].key < R[i].key)
				Imax = i;
		}
		// 将最大元素依次放在后面
		 tmp = R[Imax];
		R[Imax] = R[n - 1 - j];
		R[n - 1 - j] = tmp;
	}

}

堆排序

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

// 注意:
//		1. 当节点的索引号从0开始时,最后的非叶子节点的索引号为:n/2-1
//		2. i的左孩子为i*2+1,右孩子为i*2+2
// 用于创建初始堆及重新调整堆
void HeapAdjust(RecordType R[], int low, int high) //基于大根堆的堆排序
{ // R[low]~R[high]除R[s]外均满足堆定义,只将R[s]为根的完全二叉树调整为堆
	int i, j;
	i = low;// 调整首先从根节点开始
	RecordType tmp = R[low];// 保存根节点的值
	// 注意:对于从0开始的索引,左孩子的节点是2*i+1
	for (j = 2 * i + 1; j < high; j = 2*j+1) //沿关键字较大的孩子向下调整,先假定为左孩子
	{
		if (j +1<high&& R[j].key < R[j + 1].key)
			j += 1;  // 若右孩子集节点的关键字大则沿右孩子向下调整
		if (tmp.key >= R[j].key) break;// 即R[s]关键字已大于R[j]满足堆定义,不在进行向下调整

		R[i] = R[j];  //将关键字大的孩子节点R[j]调整至双亲节点R[i]
		i = j;      // 定位于孩子节点继续向下调整
	}
	R[i] = tmp; // 把根节点放在树中合适的位置
}
// 创建大顶堆的函数
void HeapCreate(RecordType R[], int n)// 对R[1]~R[n]这n个记录进行堆排序
{
	// 将 0~n/2-1的非叶子节点都进行操作
	for (int i = n / 2 - 1; i >= 0; i--) // 从后向前调整所有非叶子节点为根的子树,使之成为大顶堆
		HeapAdjust(R, i, n);
}

// 采用堆排序函数堆顺序表进行升序排列
void HeapSort(RecordType R[], int n)
{
	int i;
	RecordType tmp;
	HeapCreate(R, n); // 创建初始大顶堆
	for (i = n - 1 ; i > 0; i--)  // 控制堆排序共进行n-1趟
	{ // 将堆顶元素与待排范围的最后一个元素进行交换
		tmp = R[0];
		R[0] = R[i];
		R[i] = tmp;
		HeapAdjust(R, 0, i); // 将待排序的前i-1个元素重新调整为堆
	}
}

在这里插入图片描述

归并排序

递归版

在这里插入图片描述

void Merge(RecordType R[], RecordType R1[], int s, int m, int n) // 一趟二路归并排序
{ // 将有序表R[s]~R[m]及R[m+1]~R[t]合并为R1[s]~R1[t]
	int left = s, right = m ,k = s;
	while (left < m && right < n)
	{
		if (R[left].key <= R[right].key)
			R1[k++] = R[left++];
		else
			R1[k++] = R[right++];
	}
	while(left<m)
		R1[k++] = R[left++];
	while(right<n)
		R1[k++] = R[right++];
}

void MSort(RecordType R[], RecordType R1[], int s, int t)
{ // 将无序表R[s]~R[t]归并到一个有序表R1[s]~R1[t]  注意区间是左闭右开
	int m;
	RecordType R2[8];
	// 注意下标是从0开始的,且所有的区间都是左闭右开
	if (t - s == 1) { // 当区间长度小于等于1时,无需排序
		R1[s] = R[s];
	}
	else {
	
		m = (s + t) / 2;
		MSort(R,R2,s,m);// 将前半个无序表R[s]~R[m]归并到有序表R2[s]~R2[m]
		MSort(R,R2,m,t);// 将后半个无序表R2[m+1]~R2[t]归并到有序表R2[m+1]~R2[t]
		Merge(R2,R1,s,m,t); // 将有序表R2[s]~R2[m]和R2[m+1]~R2[t]归并到R1[s]~R1[t]
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

非递归版

在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述

基数排序

多关键字排序

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

链式基数排序

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

外排序

内排序方法讨论

在这里插入图片描述

提高效率

各种内排序方法比较

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值