数据结构排序算法

本文详细介绍了七种排序算法:冒泡排序、选择排序、插入排序、堆排序、希尔排序、归并排序和快速排序。通过比较,指出冒泡法是根据大小找位置,选择法确定位置来找数,选择排序法稳定度不高。此外,文章还提供了每种排序算法的工作原理和适用条件。

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

排序:就是将一组杂乱无章的数据按照一定的规律组织起来。

按照大类分为稳定排序和不稳定排序。稳定排序就是指两个大小相同的顺序在排序之后顺序不变,而不稳定排序那就不一定了。

快速排序、希尔排序、堆排序、直接选择排序不是稳定的排序算法。

详细图解如下:

 

//在这里:N(log2N)是指log以2为底N的对数

稳定排序的适用条件:1.本来就有序 2.数组比较短

 在这篇博客中会详细讲到七种排序算法,具体的过程在代码中以注释的形式体现:

1.冒泡排序:

两层循环,相邻元素进行比较

void BubbleSort(int array[], int size){
	if (size <= 1){//首先判断长度
		return;
	}
		//循环套循环,大循环遍历乱序的数组,小循环在里面进行交换。
		//有序区间逐渐变长,无序区间逐渐变短。
		int bound = 0;
		//[0,bound)当前的有序区间  [bound,size)乱序排序
		for (; bound < size; ++bound){
			//循环的目的就是找到一个最小的数字
			int cur = size - 1;
			for (; cur>bound; --cur){
				if (array[cur] < array[cur - 1])
                                    //提前定义好交换函数,直接进行调用
					Swap(&array[cur], &array[cur-1]);

			}
		}
return;
}

下面是测试代码以及主函数,经过调试结果无误:

void TestBubbleSort() {
	int array[] = { 9, 5, 2, 7 };
	BubbleSort(array, sizeof(array) / sizeof(array[0]));
        //打印数组元素的函数也是提前写好的,直接调用就可以
	PrintArray(array, sizeof(array) / sizeof(array[0]));
}

int main() {
	TestBubbleSort();
	system("pause");//防闪退
	return 0;
}

2.选择排序:

打擂台的思想,和冒泡排序十分相似,都是两层循环,但实际比较不一样

void SelectSort(int arr[], int size){
	if (size < 1){
		return;
	}
	//首先搭建出来一个有序区间
	int bound = 0;
	for (; bound < size; ++bound){
	//定义一个最小元素,比它小就交换位置
		int cur = bound;
		for (; cur < size; ++cur){
			if (arr[cur] < arr[bound]){
				Swap(&arr[cur], &arr[bound]);
			}
		}
		return;
}

小结:以上两种排序的异同点:

思想:冒泡法是根据大小找位置,而选择法是确定位置来找数

效率:选择法一次移动一个位置,效率慢,而冒泡法时间复杂度太高,同样效率也慢

稳定:选择排序法稳定度不高

3.插入排序:

(线性表)分成有序区间(0,bound)和待排序区间[bound,size},将后面的元素尝试插入有序线性表的合理位置。类似扑克牌洗牌的过程。移动的都是位置,而不是具体的数值。

void InsertSort(int arr[], int size){
	if (size < 1){
		return;
	}
	//将bound位置的元素插入到前面线性表的合理位置
	int bound = 0;
	for (; bound < size; ++bound){
		int bound_value = arr[bound];
		int i = bound;//定义一个位置
		for (; i>0; --i){
			//相比之下较大就交换,从小到大
			if (arr[i - 1]>bound_value){
				arr[i] = arr[i - 1];
				//把bound_value放在下标为i的位置上
			}
			else{
				break;//已经找到一个合适的值,跳出循环
			}
		}
		arr[i] = bound_value;//当i等于0时,循环退出
	}
}

 

4.堆排序(升序用大堆、降序用小堆)其重点在于堆的建立和删除

(1)建立大堆(上浮式 从前往后遍历、下沉式  需要从后往前遍历);

(2)循环删除堆顶元素(1、将堆顶根结点和末尾元素进行交换,此时末尾就是最大值,2、重新调整堆结构,再次调整堆顶元素和末尾元素,3、不断重复此步骤,直至满足堆的性质,变得有序)

void AdjustDown(int arr[], int size, int index){
	int parent = index;
	int child = 2 * parent + 1;//左子树
	while (child < size){
		if (child + 1 < size&&arr[child + 1] > arr[child]){
			//右子树比左子树大,指向右子树
			child = child + 1;
		}//然后和父节点进行比较
		if (arr[child]>arr[parent]){
			Swap(&arr[child], &arr[parent]);
		}
		else{//调整结束
			break;
		}
		parent = child;//作为新的起始节点
		child = 2 * parent + 1;
	}
	return;
}


void HeapCreate(int arr[], int size){
	if (size <= 1){
		return;
	}
	//下沉式调整,从最后一个非叶子节点往前遍历
	//size-1就是最后一个元素的下标
	int i = (size - 1 - 1) / 2;//当前元素的父节点
	for (; i >= 0; --i){
		AdjustDown(arr, size, i);
	}
}

void HeapPop(int arr[], int size){
	if (size <= 1){
		return;
	}
	//交换堆顶元素和末尾元素
	Swap(&arr[0], &arr[size - 1]);
	Down(arr, size - 1, 0);
}

void HeapSort(int arr[], int size) {
	if (size <= 1) {
		return;
	}
	// 1. 建立大堆,调用函数
	HeapCreate(arr, size);
	// 2. 循环删除堆顶元素
	// 每次删除一个元素, 就把当前的最大值放到数组末尾了
	int i = 0;
	for (; i < size; ++i) {
		HeapPop(arr, size - i);
	}
}

5.希尔(shell)排序:(以人名命名的一种算法),一种改进版本的插入排序

思路:将数据分组,每一组再进行插入排序

Gap步长即是组数,组内排序成功,再依次交替组成一个新的数组(插入排序)

下列情况效果比较好:长度N  步长N/2,N/4,N/8...1

void ShellSort(int arr[], int size){
	if (size <= 1){
		return;
	}
	int gap = size / 2;
	for (; gap >= 1; gap /= 2){//步长
		int bound = gap;
		for (; bound < size; bound++){
			int bound_value = arr[bound];
			int i = bound;
			for (; i >= gap; i -= gap) {
				// 第三重循环, 负责在当前组中找到一个合适位置,插入并进行搬运
				if (arr[i - gap] > bound_value) {
					arr[i] = arr[i - gap];
				}
				else{
					break;
				}
			}
			arr[i] = bound_value;
		}
	}
	return;
}

 

6.归并排序(merger):分治思想,利用递归和迭代算法

面向对象:两个有序的数组

思路:申请一个可以放下两个数组的空间,对于两个数组的开头设定两个指针,比较指针所指向的数字大小,小的直接放入新的数组,指针顺应后移。

 

7.快排:找到一个基准值

第一个下标从前往后遍历,尝试找到第一个大于基准值的元素,第二个下标从后往前遍历,尝试找到第一个小于基准值的元素,相同就交换位置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值