各类排序算法

.前言
1、本文是个人关于一些排序算法的笔记,参考:https://blog.csdn.net/qq_42453117/article/details/99680831
2、本文会使用C++和java进行实现
3、排序算法很多,日后可能会不断补充

另:
由于在排序中会大量用到两个元素间的值的交换,利用之前的C++穴道的模板的知识,先建立一个用于交换的函数:

template<class  T>
void mySwap(T& x,T& y)
{
    
    
	T temp = x;
	x = y;
	y = temp;
}

这样就可以处理各种不同数值类型的排序了。

.常用的集中排序
一、冒泡排序(Bubble Sort)
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。

图示:
在这里插入图片描述
实现代码:
C++

template<class T>
void bubbleSort(T a[],int n)
{
    
    
	int i = n - 1;
	while (i>0)
	{
    
    
		int lastExchange = 0;
		for(int j=0;j<i;j++)
		{
    
    
			if(a[j+1]<a[j])
			{
    
    
				mySwap(a[j], a[j + 1]);
				lastExchange = j;
			}
			i = lastExchange;
		}
	}
}

java

@Test
public void bubbleSort() {
    
    
	int[] arr = {
    
     3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 };
	// 统计比较次数
	int count = 0;
	// 第一轮比较
	for (int i = 0; i < arr.length - 1; i++) {
    
    
		// 第二轮比较
		for (int j = 0; j < arr.length - 1 - i; j++) {
    
    
			if (arr[j] > arr[j + 1]) {
    
    
				// 交换位置
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
			count++;
		}
	}
	System.out.println(Arrays.toString(arr));
	System.out.println("一共比较了:" + count + "次");
}

二、选择排序(Selection sort)
选择排序是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。

图示:
在这里插入图片描述
代码实现
C++

template<class T>
void selectSort(T a[],int n)
{
    
    
	for(int i=0;i<n-1;i++)
	{
    
    
		int leastIndex = i;
		for(int j=i+1;j<n;j++)
		{
    
    
			if(a[j]<a[leastIndex])
			{
    
    
				leastIndex = j;
			}
		}
		mySwap(a[i], a[leastIndex]);
	}
}

java

@Test
public void SelectionSort() {
    
    
	int[] arr = {
    
     3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 };
	for (int i = 0; i < arr.length - 1; i++) {
    
    
		int index = i;
		for (int j = 1 + i; j < arr.length; j++) {
    
    
			if (arr[j] < arr[index]) {
    
    
				index = j;// 保存最小元素的下标
			}
		}
		// 此时已经找到最小元素的下标
		// 将最小元素与前面的元素交换
		int temp = arr[index];
		arr[index] = arr[i];
		arr[i] = temp;
	}
	System.out.println(Arrays.toString(arr));
}

三、插入排序(Insertion sort)
插入排序是一种简单直观且稳定的排序算法。如果有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。
插入排序的基本思想是:每步将一个待排序的记录,按其关键码值的大小插入到前面已经排序的数组中的适当位置上,直到全部插入完为止。
图示:
在这里插入图片描述
代码实现:
C++

template<class T>
void insertionSort(T a[],int n)
{
    
    
	for(int i=1;i<n;i++)
	{
    
    
		int insertValue = a[i];

		int insertIndex = i - 1;
		while (insertIndex>=0&&insertValue<a[insertIndex])
		{
    
    
			//由于每次排序比较都要保证后面次序有序,所以无法简单直接交换
			a[insertIndex + 1] = a[insertIndex];
			insertIndex--;
		}
		a[insertIndex + 1] = insertValue;
	}
}

java

@Test
public void InsertionSort() {
    
    
	int[] arr = {
    
     3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 };
	for (int i = 1; i < arr.length; i++) {
    
    
		// 定义待插入的数
		int insertValue = arr[i];
		// 找到待插入数的前一个数的下标
		int insertIndex = i - 1;
		while (insertIndex >= 0 && insertValue < arr[insertIndex]) {
    
    
			arr[insertIndex + 1] = arr[insertIndex];
			insertIndex--;
		}
		arr[insertIndex + 1] = insertValue;
	}
	System.out.println(Arrays.toString(arr));
}

四、希尔排序
传统的插入排序算法在某些场景中存在着一些问题,例如[2,3,4,5,1]这样的一个数组,当我们对其进行插入排序的时候,发现要插入的数字是1,而要想将1插入到最前面,需要经过四个步骤,分别将5、4、3、2后移。所以得出结论:如果较小的数是我们需要进行插入的数,那效率就会比较低。鉴于这种场景的缺陷,希尔排序诞生了,它是插入排序的一种更高效的版本。
先看看希尔排序的概念:
希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因D.L.Shell于1959年提出而得名。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

图示:
在这里插入图片描述
在这里插入图片描述
代码实现
C++

template<class T>
void shellSort(T a[],int n)
{
    
    
	for(int gap=n/2;n>0;n/=2)
	{
    
    
		for(int i=gap;i<n;i++)
		{
    
    
			for(int j=i-gap;j>=0;j-=gap)
			{
    
    
				if(a[j]>a[j+gap])
				{
    
    
					mySwap(a[j], a[j + gap]);
				}
			}
		}
	}
}

java

@Test
public void ShellSort() {
    
    
	int[] arr = {
    
     3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 };
	for (int gap = arr.length / 2; gap > 0; gap /= 2) {
    
    
		// 对数组元素进行分组
		for (int i = gap; i < arr.length; i++) {
    
    
			// 遍历各组中的元素
			for (int j = i - gap; j >= 0; j -= gap) {
    
    
				// 交换元素
				if (arr[j] > arr[j + gap]) {
    
    
					int temp = arr[j];
					arr[j] = arr[j + gap];
					arr[j + gap] = temp;
				}
			}
		}
	}

	System.out.println(Arrays.toString(arr));
}

猜你喜欢

转载自blog.csdn.net/qq_43530773/article/details/114381970