数据结构之多类排序详解

【数据结构 — 排序 — 选择排序】 数据结构 — 排序 — 选择排序 阅读详情

今天分享几个排序算法:

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

1.冒泡排序

冒泡排序就是逐个比较相邻两元素,经过一轮比较把最小的元素放到最前面,相当于泡沫一样向水面上浮,或者把最大的数沉底。

冒泡排序代码实现:(我实现的是升序排序)

int bubblesort(int array[],int size){
	for (int i = 0; i < size; i++){
		int issorted = 1;			//设置一个标志位,先假设该数组是有序的
		for (int j = 0; j < size - i - 1; j++){
			if (array[j + 1] < array[j]){   //比较相邻两元素,把最大的放后面。
				swap(array, j, j + 1);
				issorted = 0;				//如果有变动就将issorted的值置为0,证明不是有序的。
			}
		}
		if (issorted == 1){				//经过一轮比较后判断issorted的值是否为1,如果为1就证明该数组已经有序。
			break;
		}
	}
}

冒泡排序图解:
在这里插入图片描述

2.直接插入排序

插入排序就是在一个有序序列里插入其他数字,最贴近我们生活的例子就是打扑克牌,最开始你的牌是无序的,但经过你的调整前面的牌就会变得有序,然后再将无序序列里的牌通过和有序序列里的牌进行比较,然后得出插入位置!

直接插入排序代码实现部分:(我实现的是降序排序)

void InsertSort(int array[], int size){ //降序排序,前面是有序序列
	for (int i = 0; i < size; i++){
		int j;
		for (j = i - 1; j >= 0 && array[j] < array[i]; j--){}//从j的序列逆着比较,遇到j中比i小的就往前走直到,直到找到合适的插入位置。
		if (j + 1 != i){
			int v = array[i];             //先记录下i处的值,否则移动后会被覆盖
			for (int k = i ; k>j+1; k--){
				array[k] = array[k - 1];
			}
			array[j+1] = v;
		}
	}
}

插入排序图解:
在这里插入图片描述

3.插入排序动态版

动态的意思就是边比较边移动数据,这个方法相比上面那个方法,少了些数据移动的过程。

下面是代码实现部分:(我实现的是升序排序)

void InsertSort2(int array[], int size){ //升序动态插入排序,边比边移动
	for (int i = 0; i < size; i++){
		int v = array[i];              //先定义一个变量v保存带插入i的值
		int j;
		for (j = i - 1; j>=0&&array[j]>v; j--){ //从有序序列j的末尾开始比较,只要比v大就往后移一位,直到不满足出循环后,然后就把那个要插入给v空出来了。
			array[j+1] = array[j];
		}
		array[j+1] = v;
	}
}

4.选择排序

选择排序就是每次假定第一个数为最大值,然后在无序序列中经过一轮和预定义的最大数比较后找出最大的数和无序序列的最后一个数交换。然后无序序列的长度每次减一。

选择排序代码实现如下:(我实现的是升序排序)

void SelectSort(int array[], int size){    //后面是有序序列
	for (int i = 0; i < size; i++){
		int max = 0;                       //每次假定无序序列的第一个数最大
		//无序[0,size-1-i]
		//有序[size-i,size-1]
		for (int j = 0; j <= size - 1 - i; j++){ //再从无序的序列中找最大的和预定义的最大比较看是否交换
			if (array[j] >= array[max]){
				max = j;
			}
		}
		Swap(array,max,size-i-1);
	}
}

选择排序图解:
在这里插入图片描述

5.快速排序

快速排序主要分为两部分一部分是确定基准值,还有部分就是再对基准值两边的区间递归使用该函数,这两个过程很重要!原来我写不出快排就是因为根本就没有记清楚快排都干了什么。

快速排序实现代码如下:(我实现的是升序排序)

//求基准值下标并进行一次排序的三种方法
//基本分治法
int partition_1(int array[], int left, int right){
	int begin = left;
	int end = right;
	int pivot = array[right];                 //定义一个变量pivot保存基准值
	while (begin < end){
		while (begin < end&&array[begin] <= pivot){
			begin++;
		}
		while (begin < end&&array[end] >= pivot){
			end--;
		}
		swap(array, begin, end);              //当同时遇到左边比基准值大,右边比基准值小的情况就交换
	}
	swap(array, begin, right);               //当begin和end相遇时说明已经走完了,则将array[right]的值和begin所在的位置的值交换
	return begin;
}

//双下标法
int partition_2(int array[], int left, int right){ 
	int d = left;						//d会停在第一个大于array[right]的数上
	for (int i = left; i < right; i++){   //向后找比array[right]小的就和d所在位置的数交换,
		if (array[i] < array[right]){     //直到i走完为止
			swap(array, i, d);
			d++;
		}
	}
	swap(array,d,right);                 //交换d和right的值
	return d;
}

//挖坑填坑法                  该方法比基本分治法要快一些,因为它少了交换的次数
int partition_3(int array[], int left, int right){
	int begin = left;
	int end = right;
	int pivot = array[right];             //先找个变量保存array[right],此时把end所在的位置看作是个坑
	while (begin < end){
		while (begin < end&&array[begin] <= pivot){
			begin++;
		}
		array[end] = array[begin];    //只要遇到begin的值比pivot的值大就用begin的值来填end所在的坑,然后这样begin的位置就成了一个坑
		while (begin < end&&array[end] >= pivot){
			end--;
		}
		array[begin] = array[end];    //当遇到end的值比pivot小的时候再用end的值去填刚才begin那个位置的坑,这样end所在的位置就变成了一个坑,然后再循环上面操作。
	}
	array[begin] = pivot;           //当begin和end相遇后证明已经走完,将pivot的放到begin所在的位置,这样就做到了pivot左边的都比它小,pivot右边的都比它大
	return begin;
}

void Qsort(int array[], int left, int right){
	if (left == right){            //如果左边界和右边界相等证明只有一个数了,那就是有序的
		return;
	}
	if (left > right){            //如果左边界大于右边界证明区间里没有数,已经结束了
		return;
	}
	int d = partition_3(array, left, right);  //获取基准值下标
	Qsort(array, left, d - 1);                //对基准值左边的区间递归调用该函数
	Qsort(array, d + 1, right);               //对基准值右边的区间递归调用该函数
}

void quicksort(int array[], int size){
	Qsort(array, 0, size - 1);
}

快速排序图解:
在这里插入图片描述

6.归并排序

归并排序就是每次求出中间位置将一个区间划分为左右两个小区间,再对两个小区间分别递归进行归并排序。归并排序和快排很类似,但也有着实质性的区别原理不同,快排是确定一个基准值,保证一次排序后基准值左边的数都小于基准值,基准值右边的数都大于基准值;而归并排序是不断合并两个有序区间达到最终的排序目的。

归并排序代码实现部分:(我实现的是升序排序)

void merge(int array[], int low, int mid, int high, int extra[]){  //合并两个有序区间,类比两个链表的合并
	int i = low;
	int j = mid;
	int k = low;
	while (i < mid&&j < high){
		if (array[i] <= array[j]){   //保证稳定性
			extra[k++] = array[i++];
		}
		else{
			extra[k++] = array[j++];
		}
	}
	while (i < mid){          //前面的区间还剩的有
		extra[k++] = array[i++];
	}
	while (j < high){		 //后面的区间还剩的有
		extra[k++] = array[j++];
	}
	for (int x = low; x < high; x++){   //把合并后的有序区间再重新赋值给原区间
		array[x] = extra[x];
	}
}

void mergrinner(int array[],int low,int high,int extra[] ){   //左闭右开
	if (low >= high){               //左边界>=右边界的话,说明区间就没有数,因为我是采用左闭右开的方式定义区间的。
		return;
	}
	if (low +1 == high){           //左边界+1=右边界的话说明区间只有一个数,也就说明是有序的
		return;
	}
	int mid = low + (high - low) / 2;  //找区间的中间位置
	mergrinner(array, low, mid, extra); //对mid左边的区间递归调用该函数
	mergrinner(array, mid, high, extra); //对mid右边的区间递归调用该函数
	merge(array, low, mid, high, extra); //当左右区间有序时则会调用该函数来合并两个有序区间
}

void mergesort(int array[],int size){
	int *extra = (int*)malloc(sizeof(int)*size); //在主调函数内申请空间
	mergrinner(array, 0, size, extra);
	free(extra);                    //释放所调用的空间
}

归并排序图解:
在这里插入图片描述

7.堆排序

如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

拿我所写的代码解释堆排序就是每次通过向下调整的方式将最大的数置于堆顶,然后将堆顶元素和数组中的最后一个元素交换,这样每经过一轮就将最大的数放到数组无序数组末尾,每找到一个最大数后无序数组长度减一!

牢记:升序排序建大堆,降序排序建小堆!

堆排序代码实现如下:(我实现的是升序排序)

void Heapify(int array[], int size, int index){   //向下调整
	int leftindex = index * 2 + 1;
	while ((2 * index + 1) < size){        //如果是叶子结点就不需要进入循环
		int rightindex = index * 2 + 2;
		int max = leftindex;
		if (rightindex<size&&array[rightindex]>array[max]){
			max = rightindex;
		}
		if (array[max] <= array[index]){
			return;
		}
		int tmp = array[max];
		array[max] = array[index];
		array[index] = tmp;
		index = max;
	}
}


void CreateHeap(int array[],int size){      //因为写的是升序排序所以建大堆,如果是一个堆的话那么它下面一定满足是堆
	for (int i = size/2 - 1; i >= 0; i--){   //因此向上调整
		Heapify(array,size,i);               //因为向下调整函数参数传的是最后一个非叶子结点的下标所以进行的是向上调整
	}
}

void HeapSort(int array[], int size){ //升序建大堆
	CreateHeap(array, size);         //创建大堆
	for (int i = 0; i < size; i++){
		Swap(array,0,size-1-i);      //将堆顶(最大元素)和无序序列最后一个元素交换
		Heapify(array, size-1-i,0);  //然后堆顶一变就需要向下调整,并且无序序列长度-1
	}

堆排序图解:在这里插入图片描述

8.各类排序的比较和分析

排序方法平均情况最好情况最坏情况辅助空间稳定性
冒泡排序O(n^2)O(n)O(n^2)O(1)稳定
直接插入排序O(n^2)O(n^2)O(n^2)O(1)稳定
选择排序O(n^2)O(n^2)O(n^2)O(1)不稳定
快速排序O(nlogn)O(nlogn)O(n^2)O(logn)~O(n)不稳定
堆排序O(nlogn)O(nlogn)O(nlogn)O(1)不稳定
归并排序O(nlogn)O(nlogn)O(nlogn)O(n)稳定

最后给大家提供一个网址,里面是关于排序的视频讲解,不过是通过舞蹈的形式体现出来的,希望能够帮助大家理解:https://www.bilibili.com/video/av17449274?from=search&seid=3210928110498774502

【数据结构排序算法系列】数据结构八大排序算法 排序算法在计算机应用中随处可见,如Windows操作系统的文件管理中会自动对用户创建的文件按照一定的规则排序(这个规则用户可以自定义,默认按照文件名排序)因此熟练掌握各种排序算法是非常重要的,本博客将对数据结构中常见的八大排序算法进行详细的讲解。 写在前面的话:首先要明白在学习同类型的排序算法时,一定要明白任何相同领域存在的东西一定是竞争之后的结果,所以对于相同类型的排序之所以能够存在多种被人熟 阅读详情

相关推荐

「数据结构详解·十二」有向无环图 & 拓扑排序

DAG、拓扑排序详解

Leo_Chenjy的博客 3872

解决多级排序问题的思路

呃呃呃就是写了一道题写的很难受,然后同学说可以参考sort函数,我就觉得挺妙的,然后就记录一下。

ajole的博客 531

数据结构之九大排序(JAVA)

最近面临实习面试,由于自己准备投开发岗,据了解在面试中对于数据结构的考察是很重要的,其中对于查找、排序的算法考察尤为重要,所以又重回当年学习的数据结构好好复习。参考:《数据结构》 严蔚敏版、《考研数据结构》及各排序总结博客,整理出适合自己的排序总结以供参考 http://www.open-open.com/lib/view/open1453126714683.html http://www

Aka丶的博客 9467

数据结构——排序1

排序的基本概念 排序:给定一组记录的集合{r1, r2, ……, rn},其相应的关键码分别为{k1, k2, ……, kn},排序是将这些记录排列成顺序为{rs1, rs2, ……, rsn}的一个序列,使得相应的关键码满足ks1≤ks2≤……≤ksn(称为升序)或ks1≥ks2≥……≥ksn(称为降序)。 正序:待排序序列中的记录已按关键码排好序。 逆序(反序):待排序序列中记录的排列顺序与排...

weixin_45212219的博客 335

【自考】数据结构之排序

入排序:将记录分为有序和无序区,让无序区中的记录依次插入到有序区中,并保持有序。 交换排序:两两比较待排序记录,当记录之间键值出现逆序时,则互换位置。 选择排序:每次从待排序记录中选取键值最小或最大的记录放在适当的位置。 归并排序:将两个或两个以上的有序表合并成一个有序

Dwyane 1980

数据结构中十大排序算法 详解

排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

Hanshy123的博客 1762

常见排序算法原理及其java实现

本文对主要排序算法:冒泡排序、选择排序、直接插入排序、希尔排序、快速排序、归并排序、堆排序、桶排序等的基本思想进行了讲解,并利用java对其进行了实现

皮皮狗 423

【实战】ESP32 + LN298N 实现电动推杆的闭环位置伺服控制

本文详细介绍了如何使用ESP32微控制器和LN298N电机驱动模块,为普通电动推杆增加编码器反馈,实现精准的闭环位置伺服控制。文章从硬件选型与接线讲起,深入解析了编码器四倍频计数原理与位置换算,并重点阐述了PID控制算法的核心思想、代码实现及参数整定方法,旨在帮助读者从零构建一个反应迅速、定位精准的智能执行器系统。

weixin_29195615的博客 318

多级排序!

Description 经过了一个前一段时间对数据结构中排序一章的学习,相信大家对排序也有了较深的感情。当然,这就是一个简单的排序问题,try to do it ^_^! 在众多的排序算法中,你会如何选择呢?假设现在需要你实现一个小学生成绩管理系统,要求把成绩好的同学放到前面的。我们首先是按个人的总成绩进行排名,如果某两个人的总分相同,则按他们的语文成绩进行排名,如果总成绩和语文成绩都相同时,对于

江湖小小生 1837

从信号到振镜:STM32F103 + XY2-100协议 + AM26LS31芯片的激光打标/雕刻系统信号链搭建指南

本文详细介绍了基于STM32F103微控制器和XY2-100协议的激光打标/雕刻系统信号链搭建方法。从数字振镜控制协议解析、AM26LS31差分驱动电路设计到信号完整性优化,提供了一套完整的解决方案,帮助工程师实现高精度激光控制系统的开发与调试。

weixin_42536058的博客 236

halcon 检测直线

图中后三个对象既是检测出的图像;

qq_59062726的博客 666

C++结构体多级排序的三种方法

C++结构体多级排序的三种方法 struct node{ int chinese,math; char name[15]; }; 需求:按数学成绩从大到小排序  1.自定义比较器 //自定义比较函数 bool cmp(node a,node b){ return a.math&gt;b.math; } 2.定义友元函数 struct node{ int chines...

紫芝的博客 4201

Win10如何使用BC3.1精简版

Win10如何使用BC3.1精简版 使用Borland C++3.1 学习μC/OS—Ⅱ几乎是现在的普遍做法,但是由于Win10系统不能直接使用BC3.1,所以需要用到DOSBox。 1、解压bc3.1精简版压缩包,本文将BC3.1文件夹复制在D盘下,DOSBOX按照默认路径安装。下图为两者安装目录图示: 2、修改DOSBOX的配置文件,找到DOSBox文件安装路径,记事本方式打开DOSBox 0.74-3 Options.bat文件,在此文件末尾添加: MOUNT C D:\BC//意为把D:\BC目录

qq_45547236的博客 2377

数据结构六大排序详解(插入排序、希尔排序、选择排序、冒泡排序、快速排序、堆排序)

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

weixin_45796387的博客 6612

模型优化系列——模型剪枝/量化概述

模型优化目的:通过减少模型大小,提高推理速度等使模型成功部署在各个硬件中并实时有效运作。

qq_61210574的博客 1293

移花接木,玩转CANoe的几种扩展接口应用(五)——串口设备

近期看到粉丝朋友在CANoe自动化测试方面的关注度很大,今天就围绕这个做一个专题,总结一下以往项目上用过的几种CANoe扩展接口,分享出来希望对相关领域的网友有所帮助。本文是该专题的第五篇文章,主要讲解了串口设备的功能配置、连接方法、配置方法、调用方法,最后分析了这种扩展借口应用的特点和适用场景。

Mr.Cssust的博客 2369

数据结构——【排序】详解

一. 排序💨 1.1 基本概念 排序(sorting)又称分类,就是将一组任意序列得数据元素按一定得规律进行排列(按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作),使之成为有序序列。 平时的上下文中,如果提到排序,通常指的是排升序(非降序)。 通常意义上的排序,都是指的原地排序(in place sort)。 1.2 稳定性 定义:数组 arr 中有若干元素,其中 A元素和 B元素相等,并且 A元素在 B元素前面,如果使用某种排序算法排序后,能够保证 A元素依然在 B元素的前面,可

Lucky_mzc的博客 1万+

STEP 7-Micro/WIN SMART 编程软件:从入门到精通的使用指南

通过不断实践,熟悉软件的各项功能和操作技巧,工程师可更好地应对工业自动化控制中的各种挑战,开发出高效、稳定的控制程序。项目的基本组件是构成程序的核心元素,包括:程序块(主程序 OB1、子程序和中断程序)、数据块(给 V 存储器赋初值)、系统块(硬件组态和参数设置)、符号表(用符号代替存储器地址,使程序更易理解)以及状态图表(监视、修改和强制变量状态)。下载程序时,单击工具栏上的 “下载” 按钮,在弹出的下载对话框中选择要下载的块(程序块、数据块、系统块),单击 “下载” 即可。

电工 5573

22计算机408考研—数据结构—排序(详解加例题)

排序 排序的基本概念 顾名思义,给一个无序数组的值进行顺序存储 原数组:2 3 1 5 6 4 8 9 7 排序后:1 2 3 4 5 6 7 8 9 直接插入排序 思路: 插入 == 把数插进去 也是两层循环 数组num 第一层循环从下标为1的值开始,循环变量为i 第二层循环就是把第一层的值拿出来,然后从第i-1个向前循环,找到第一个小于num[i]的值, 这个值的下标如果是j-1的话,那么num[j]就是第一个大于num[i]的值 把num[i]用一个变量temp保存一下 把下标为j到i-1的值依次向

日常发呆 2万+

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

数据结构:排序(Sort)【详解】

友情链接:数据结构专栏 目录排序【知识框架】排序概述一、排序的相关定义二、排序用到的结构与函数常见的排序算法一、冒泡排序 排序 【知识框架】 排序概述 一、排序的相关定义 排序,就是重新排列表中的元素,使表中的元素满足按关键字有序的过程。为了查找方便,通常希望计算机中的表是按关键字有序的。排序的确切定义如下: 输入:nnn个记录R1,R2,...,RnR_1,R_2,...,R_nR1​,R2​,...,Rn​,对应的关键字为k1,k2,...,knk_1,k_2,...,k_nk1​,k2​,...

UniqueUnit的博客 2万+

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

【排序算法】数据结构排序详解

排序算法的实现

m0_56069910的博客 1680

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

【数据结构】——十大排序详解分析及对比

排序算法是《数据结构》中最基本的算法之一我们先来大致简单了解一下排序算法吧排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存根据排序的特点可以将排序分为:直接插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、归并排序等

2302_78420373的博客 2707

数据结构——排序

数据结构,排序

2303_78442132的博客 2591

数据结构——希尔排序(详解)

数据结构算法——希尔排序

Yui_的博客 1万+

数据结构——堆的应用 堆排序详解

以上就是堆的应用——堆排序啦~,我们发现可以不用写堆的实现代码就可以将一个数组排成堆🥳🥳,关键在于堆向上调整与向下调整算法的理解与运用,大家都学废了吗 ,💞💞 完结撒花 ~🎉🎉🎉。

Renswc的博客 3612
上一篇: 数据结构之二叉树介绍
下一篇: 剑指offer_01 二维数组中的查找
Python_programer
博客等级 码龄9年 25粉丝 57原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值