数据结构:冒泡排序,选择排序,插入排序,希尔排序的实现分析

✨✨小新课堂开课了,欢迎欢迎~✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:数据结构与算法

小新的主页:编程版小新-CSDN博客

1.冒泡排序

1.1算法思想

冒泡排序的基本思想就是,遍历原数组的元素,比较相邻的两个元素,如果这两个元素的顺序不对,就是把这两个元素交换,直到都不需要交换的时候,排序结束。

1.2具体步骤

比较相邻的两个元素,把大的(小的)往后换,就这样重复此步骤,每遍历完数组一次,就能将最大的(最小的)元素放在最后。重复遍历该数组,直至都不需要交换的时候,排序就结束了。

1.3动图演示

1.4代码实现

cs 复制代码
void Swap(int*a,int*b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
//冒泡排序
void BubbleSort(int* arr, int len)
{
	for (int i = 0; i < len - 1; i++)//比较次数
	{
		for (int j = 0; j < len-1-i; j++)//单趟比较
		{
			if (arr[j] > arr[j + 1])
			{
				Swap(&arr[j], &arr[j + 1]);
			}
		}
	}
}

有的时候不用遍历数组len次,排序就已经排好了,我们知道遍历完数组一次后,如果不存在交换,那就不用再继续比较了。此时排序已经排好了。

优化:

cs 复制代码
void Swap(int*a,int*b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
//冒泡排序
void BubbleSort(int* arr, int len)
{
    int flag = 0;
	for (int i = 0; i < len - 1; i++)//比较次数
	{
		for (int j = 0; j < len-1-i; j++)//单趟比较
		{
			if (arr[j] > arr[j + 1])
			{
				Swap(&arr[j], &arr[j + 1]);
                flag = 1;
			}
		}

        if(flag ==0)//未发生交换,排序已经完成
           break;
	}
}

1.5复杂度分析

**时间复杂度:**这里很容易就能看出来是O(N^2)。以最坏的情况来看,n-1+n-2+n-3+......+2+1=n*(n-1)/2。

**空间复杂度:**因为没有额外的开空间,所以空间复杂度为O(1)。

1.6稳定性分析

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

简而言之,相同值相对位置不变称之为稳定。

冒泡排序是相邻位置的元素比较,决定交不交换,一样的元素,在排序过程中相对位置不会发生变化,因此冒泡排序是稳定的

2.选择排序

2.1算法思想

遍历原数组,找出最小或者最大的那个元素,与起始位置或则末尾的元素交换,每遍历完一次,起始位置向后移(末尾的位置往前移),当起始位置移到最后一个位置时(末尾位置移到数组的第一个元素的位置时),排序结束。

2.2具体步骤

遍历数组,找到最大或者最小的元素,与起始位置交换。

从剩余的元素中找继续找最大或最小的元素,排到已排序序列的末尾。

以此类推,直到所有的元素都排列完毕。

2.3动图演示

2.4代码实现

基于动态演示实现的代码:

cs 复制代码
void SelectSort(int* arr, int len)//选择排序
{
	for (int i = 0; i < len - 1; i++)//起始位置
	{
		int mini = i;
		for (int j = i + 1; j < len; j++)//寻找最小元素
		{
			if (arr[j] < arr[mini])
			{
				mini = j;
			}
		}
		swap(&arr[mini], &arr[i]);
	}
}

上面的代码效率比较低,我们在遍历一遍数组的时候,可以找到该数组中最大和最小的元素,让最大的元素与end交换,最小的元素与begin交换,不断的这样缩小区间,完成排序。

这里要注意的是,我们在交换的时候,可能会改变最大或最小元素的位置 。

cs 复制代码
//选择排序

void Swap(int*a,int*b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}


void SelectSort(int* arr, int len)
{
	int begin = 0;
	int end = len - 1;
	while (begin < end)
	{
		int mini = begin;
		int maxi = begin;
		for (int i = begin + 1; i <=end; i++)
		{
			//遍历一遍找最大和最小
			if (arr[i] > arr[maxi])
			{
				maxi = i;
			}

			if (arr[i] < arr[mini])
			{
				mini = i;
			}

		}
		Swap(&arr[begin], &arr[mini]);

		if (maxi == begin)//如果begin和maxi重合,就要对maxi更正
		{
			maxi = mini;
		}

		Swap(&arr[end], &arr[maxi]);
		begin++;
		end--;
	}
}

2.5复杂度分析

**时间复杂度:**优没优化,算时间复杂度的时候都是等差数列,时间复杂度为O(N^2)。

**空间复杂度:**没有额外开辟空间,因此空间复杂度为O(N)。

2.6稳定性分析

3.插入排序

3.1算法思想

把待排元素逐一与已排序的部分元素进行比较,把它插入到已排序序列中的适当位置,直到把元素全部插入完毕。

3.2具体步骤

把第一个元素看成有序序列,从第二个元素开始,将该元素与前面已排好序的元素比较,如果该元素比较小,就将前面的元素依次往后移动一位,将该元素插入到腾出的位置上。

重复上面的插入过程,直至整个序列都被排序完成。

3.3动图演示

3.4代码实现

cs 复制代码
// 插入排序
void InsertSort(int* a, int n)
{
	//【0-end】有序,将end+1的值插入到区间内,形成新的区间
	for (int i = 0; i < n - 1; i++)
	{
		int end = i;
		int tmp = a[end + 1];
		while (end >= 0)
		{
			
			if (a[end] > tmp)
			{
				a[end + 1] = a[end];//往后移
				end--;
			}
			else
			{
				break;//找到合适的位置了
                      //也有可能合适的位置就是数组的起始位置,没有进break,此时end为-1越界,在
                      // end+1的位置插入,就是把该元素插入到起始位置
			}
		}
		a[end + 1] = tmp;//在腾出来的位置插入该元素
	}

}

3.5复杂度分析

**时间复杂度:**以最坏的情况,逆序来算,移动的次数是等差数列的前n-1项和,O(N^2)。

**空间复杂度:**没有额外开辟空间,空间复杂度为O(1)。

3.6稳定性分析

插入排序不会改变相同元素的相对位置,在前面的和在后面的那个在插入到腾出的位置后,还是一前一后。因此插入排序稳定

4.希尔排序

4.1算法思想

希尔排序是对插入排序的改进。它先将整个待排的序列分割成若干个子序列,对每一个子序列分别进行插入排序,然后不断缩小缩小子序列的间隔,重复这个过程直至间隔为1 时进行一次完整的插入排序。

4.2具体步骤

希尔排序分为两步:1.预排序(使数组接近有序) 2.插入排序

选取一个gap,间隔gap个数据为一组,把整个数组进行分组,一共gap组。

以gap为基准,对其进行插入排序。

不断缩小gap,直至gap为1,进行一次完整的插入排序。

gap>1时是在进行预排序,gap==1是在进行直接插入排序。

4.3动图演示

4.4代码实现

cs 复制代码
// 希尔排序
//希尔排序分为两步:第一步是预排序(使其接近有序),第二步是进行插入排序
void ShellSort(int* a, int n)
{
	int gap = n;//gap代表每间隔gap个为一组即一共分成gap组
	while (gap > 1)
	{
		//gap>1是进行预排序
		//gap==1是在进行插入排序
		gap = gap / 3 + 1;//+1是保证最后一组gap一定为1,
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = a[end + gap];//i之所以小于n-gap;是防止这里越界
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	
	}
}

4.5复杂度分析

时间复杂度:希尔排序的时间复杂度可以直接记,因为比较难算。O(N^1.3)

**空间复杂度:**没有额外开辟空间,空间复杂度为O(1)。

4.6稳定性分析

在排序过程中,可能相同数据分到不同的组,这个无法控制,因此希尔排序不稳定

相关推荐
y_m_h28 分钟前
leetcode912.排序数组的题解
数据结构·算法
1 9 J29 分钟前
数据结构 C/C++(实验三:队列)
c语言·数据结构·c++·算法
921正在学习编程34 分钟前
数据结构之二叉树前序,中序,后序习题分析(递归图)
c语言·数据结构·算法·二叉树
毕竟秋山澪1 小时前
岛屿数量 广搜版BFS C#
数据结构·算法·宽度优先
乔冠宇2 小时前
环状 DNA 序列的最小表示法
java·数据结构·算法
vir022 小时前
找出目标值在数组中的开始和结束位置(二分查找)
数据结构·c++·算法·leetcode
薄荷冰ovo2 小时前
C++中的提供的四种类型转换方式;
数据结构·c++
小刘|3 小时前
《Java 实现选择排序:原理剖析与代码详解》
java·算法·排序算法
CodeHackerBhx3 小时前
归并排序和随机化快速排序
数据结构·算法·排序算法
福楠5 小时前
[LeetCode] 1137. 第N个泰波那契数
数据结构·c++·算法·leetcode