百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

排序算法总结(排序算法总结体会)

toyiye 2024-07-08 00:30 12 浏览 0 评论

一.插入排序

1.直接插入排序

  • 原理:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
  • 时间复杂度:最坏情况O(n^2),最好情况O(n)(当输入序列已排序时)。
  • 空间复杂度:O(1)(原地排序)。
  • 稳定性:稳定。
 void InsertSort(int arr[], int arrlen)
{
	if(arrlen <= 1)
		return;
	
	for(int i = 1 ; i < arrlen; ++i)
	{
		int data = arr[i];
		int j = i - 1;
		for(; j >= 0; j--)
		{
			if(data >= arr[j])
				break;
		}
		
		if(j< i - 1)
		{
			for(int m = i; m > j + 1; --m)
			{
				arr[m] = arr[m - 1];
			}
			arr[j + 1] = data;
		}
	}
}

2.折半插入排序

  • 原理:基于直接插入排序原理,只是插入比较时使用二分查找来确定插入位置。
  • 时间复杂度:最坏情况O(n^2),最好情况O(n)(当输入序列已排序时)。
  • 空间复杂度:O(1)(原地排序)。
  • 稳定性:稳定。
void BinaryInsertSort(int arr[], int arrlen)
{
	if(arrlen <= 1)
		return;
	
	for(int i = 1; i < arrlen; ++i)
	{
		int data = arr[i];
		int begin = 0, end = i - 1, half = 0;
		
		while(end >= begin)
		{
			half = (begin + end) / 2;
			if(data >= arr[half]) //必须是>=,这样才能保证排序稳定。
			{
				begin = half + 1;
				half = half + 1;
			}
			else
			{
				end = half - 1;
			}
		}
		
		if(half < i )
		{
			for(int m = i; m > half; --m)
			{
				arr[m] = arr[m - 1];
			}
			arr[half] = data;
		}
	}
}

3.希尔排序

  • 原理:是插入排序的一种更高效的改进版本,将待排序的数组元素按下标的一定增量分组,对每组使用直接插入排序算法排序。随着增量逐渐减少,每组包含的元素越来越多,当增量减至1时,整个数组恰被分成一组,算法便终止。这种分组排序的思想减少了元素之间的比较和移动次数,从而提高了排序效率。
  • n个元素直接插入排序平均时间复杂度为o(n^2),那么分为d组,每组n/d个元素,时间复杂度为d*(n/d)^2=n^2/d。
  • 分组时d越大优化越明显,初始值一般取数组的1/2。
  • 时间复杂度:依赖于增量序列的选择,范围在O(n log2 n)到O(n2)之间,平均O(n^1.3)
  • 空间复杂度:O(1)(原地排序)。
  • 稳定性:不稳定。
void ShellSort(int arr[], int arrlen)
{
	if(arrlen <= 1)
		return;
	int d = arrlen / 2;
	
	for(; d > 0; --d)
	{
		for(int c = 0; c < d; ++c)
		{
			for(int i = c + d ; i < arrlen; i = i + d) //步长改成d,直接调用直接插入排序算法。
			{
				int data = arr[i];
				int j = i - d;
				for(; j >= 0; j = j - d)
				{
					if(data >= arr[j])
						break;
				}
				
				if(j< i - d)
				{
					for(int m = i; m > j + d; m = m -d)
					{
						arr[m] = arr[m - d];
					}
					arr[j + d] = data;
				}
			}
		}
	}
}

二.交换排序

1.冒泡排序

  • 原理:通过重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
  • 时间复杂度:最坏情况O(n^2),最好情况O(n)(当输入序列已排序时)。
  • 空间复杂度:O(1)(原地排序)。
  • 稳定性:稳定。
void BubbleSort(int arr[], int arrlen)
{
	bool bchange = false;
	for(int n = 0; n < arrlen - 1 ; ++n)
	{
		bchange = false;
		for(int i = 0; i < arrlen - 1 - n; ++i)
		{
			if(arr[i] > arr[i+1])
			{
				int tem = arr[i];
				arr[i] = arr[i+1];
				arr[i+1] = tem;
				bchange = true;
			}
		}
		if(bchange == false)
			break;
	}
}

2.快速排序

  • 原理:是一种高效的排序算法,它使用了分而治之的策略。快速排序的基本思想是通过一次排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
  • 时间复杂度:平均情况O(n log n),最坏情况O(n^2)(当输入序列已排序或逆序时)。
  • 空间复杂度:O(log n)(递归栈空间,最好情况),O(n)(最坏情况)。
  • 稳定性:不稳定。
 void QuickSort(int arr[], int arrlen)
{
	if(arrlen < 1)
		return;
	int i = 0, j = arrlen - 1;
	int v = arr[0];
	while(i != j)
	{
		for(; j != i; --j)
		{
			if(arr[j] < v)
			{
				arr[i] = arr[j];
				break;
			}
		}
		
		for(; i != j; ++i)
		{
			if(arr[i] > v)
			{
				arr[j] = arr[i];
				break;
			}
		}
	}
	assert(i == j);
	arr[i] = v;
	
	QuickSort(arr, i);
	QuickSort(arr + i + 1, arrlen - i - 1);
}

三.选择排序

1.直接选择排序

  • 原理:首先在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
  • 时间复杂度:O(n^2)。
  • 空间复杂度:O(1)(原地排序)。
  • 稳定性:不稳定。
void SelectSort(int arr[], int arrlen)
{
	if(arrlen <= 1)
		return;
	
	int min, orgin, index;
	for(int i = 0; i < arrlen - 1; ++i)
	{
		min = arr[i];
		index = i;
		orgin = arr[i];
		for(int cn = i + 1; cn < arrlen; ++cn)
		{
			if(arr[cn] < min)
			{
				min = arr[cn];
				index = cn;
			}
		}
		arr[i] = arr[index];
		arr[index] = orgin;
	}
}

2.堆排序

  • 原理:是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。
  • 时间复杂度:O(n log n)。
  • 空间复杂度:O(1)(原地排序)。
  • 稳定性:不稳定。
//把数组arr从index元素开始,len个元素大堆化。
/*
 @param *arr,需要排序的数组
 @param index, 数组开始的元素
 @param len,需要构建大堆的元素个数
 */
void Heapify(int *arr, int index, int len)
{
	if(index >= len)
		return;
	
	//root:n, LChild:2n + 1, RChild:2n + 2。
	int maxindex = index, maxv = arr[index], lindex = 2 * index + 1, rindex = 2 * index + 2;
	
	int lv = maxv, rv = maxv;
	if(lindex < len)
		lv = arr[lindex];
	if(rindex < len)
		rv = arr[rindex];
	
	if(lv > maxv)
	{
		maxindex = lindex;
		maxv = lv;
	}
	if(rv > maxv)
	{
		maxindex = rindex;
		maxv = rv;
	}
	
	if(maxindex != index)//需要调整
	{
		swap(arr[index], arr[maxindex]);
		//递归的调整受影响的子堆。
		Heapify(arr, maxindex, len);
	}
	
}


//原理:是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。
//时间复杂度:O(n log n)。
//空间复杂度:O(1)(原地排序)。
//稳定性:不稳定。
/*
 @param arr[],需要排序的数组
 @param arrlen,待排序的数组长度
 */
void HeapSort(int arr[], int arrlen)
{
	if(arrlen <= 1)
		return;
	
	//n个结点的完全二叉树,最后一个非叶子结点的索引是 n/2 - 1
	int lastn = arrlen / 2 - 1;
	
	//从最后一个非叶子结点开始构建最大堆
	for(int n = lastn; n >= 0; --n)
	{
		Heapify(arr, n, arrlen);
	}

	for(int i = 0; i < arrlen - 1; ++i)
	{
		//把根节点最大元素和末尾元素交换
		swap(arr[0], arr[arrlen - 1 -i]);
		
		//交换后调整最大堆
		Heapify(arr, 0, arrlen - 1 - i);
	}
	
}

四.归并排序

  • 原理:采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
  • 时间复杂度:O(n log n)。
  • 空间复杂度:O(n)(非原地排序,需要额外的存储空间)。
  • 稳定性:稳定。
/*
 @param arr[],需要排序的数组
 @param len,待排序的数组长度
 @param start, 待排序数组起始索引
 */
void MergeSort(int arr[], int len, int start = 0)
{
	if(len<=1)
		return;
	int leftlen = len / 2;
	int rightlen = len - leftlen;
	
	MergeSort(arr, leftlen, start);
	MergeSort(arr,  rightlen, start + leftlen);
	
	int* temp = new int[len];
	int i = start, j = start + leftlen, index = 0;
	
	for(; i < start + leftlen;)
	{
		if(j == start + len)
		{
			temp[index++] = arr[i++];
			continue;
		}
		for(;j < start + len;)
		{
			if(arr[i] <= arr[j])
			{
				temp[index++] = arr[i];
				++i;
				break;
			}
			else
			{
				temp[index++] = arr[j];
				++j;
			}
		}

	}
	
	for(;j < start + len; ++j)
	{
		temp[index++] = arr[j];
	}
	assert(index == len);
	for(int i = 0; i < len; ++i)
	{
		arr[start + i] = temp[i];
	}
	
	delete [] temp;
}

测试用例

int main()
{
	std::random_device rd; // 用硬件生成种子  
	std::mt19937 gen(rd()); // 以随机设备作为种子的Mersenne Twister生成器  
	// 定义随机数的范围  
	std::uniform_int_distribution<> dis(1, 100); // 定义一个在1到100之间的均匀分布  
	vector<int> vec;
	int sum = 0, checksum = 0;
	for(int cn = 0 ; cn < 10000; ++cn) //1000次测试
	{
		for(int arrlen = 1; arrlen < 50; ++arrlen)
		{
			vec.clear();
			sum = 0;
			int* arr = new int[arrlen];
			
			for(int m = 0; m < arrlen; ++m)
			{
				arr[m] = dis(gen);   // 生成随机数  
				vec.push_back(arr[m]);
				sum += arr[m];
			}
			
			//QuickSort(arr, arrlen);
			//BubbleSort(arr, arrlen);
			//InsertSort(arr, arrlen);
			//BinaryInsertSort(arr, arrlen);
			//ShellSort(arr, arrlen);
			//SelectSort(arr, arrlen);
			//HeapSort(arr, arrlen);
			MergeSort(arr, arrlen);
			checksum = arr[0];
			for(int i = 0; i < arrlen - 1; ++i)
			{
				checksum += arr[i+1];
				if(arr[i] > arr[i + 1])
				{
					for_each(vec.begin(), vec.end(), [](int v){
						cout << " " << v;
					});
					delete [] arr;
					assert(false);
					cout << "error!" << endl;
					return 0;
				}
			}
			assert(checksum == sum);
			delete [] arr;
		}
		if(cn % 200 == 0)
			cout << "test " << cn << " cnt finish" << endl;
	}
	return 0;
}


众所周知如果递归层次过多,就会超出操作系统的栈大小,从而导致爆栈程序崩溃,以上排序算法有不少使用了递归,你能根据上篇文章改写成循环吗,或者有初学者需要,评论区留言我来改写。

#长文创作激励计划##排序算法##编程#

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码