冒泡排序、选择排序、直接插入排序、希尔排序

冒泡排序

冒泡法排序思路如下:

  • 设有n个数,从前向后对相邻两个数比较(共比较n-1次),将小数交换到前面,大数交换到后面。逐次比较,直到将最大的数移到最后为止(此时最大的数在最后,固定下来,目前固定了一个最大数)。

  • 剩下前面n-1个数,从前向后,对相邻两个数进行比较(共比较(n-1)-1)=n-2次,将小数交换到前面,大数交换到后面。逐次比较,直到将次大的数移到倒数第二个位置上为止(此时次大的数在倒数第二个位置上,同样被固定了下来,目前固定了两个大数)。

  • 余下前面的n-i个数,从前向后,对相邻两个数进行比较(共比较n-i-1次),将小数交换到前面,大数交换到后面。逐次比较,直到将第i+1个大数移到第i+1个位置上为止(也称为大数沉底)。

代码如下:

int Partion(int *arr, int low, int high)//找基准
{
	int tmp = arr[low];//tmp用来保存第一个元素的值
	while (low < high)
	{
		while (arr[high] > tmp&&low < high)
		{
			high--;
		}
		if (arr[high] < tmp)
		{
			arr[low] = arr[high];
		}
		else
		{
			break;
		}
		while (arr[low] < tmp&&low < high)
		{
			low++;
		}
		if (arr[low] > tmp)
		{
			arr[high] = arr[low];
		}
		else
		{
			break;
		}
	}
	arr[low] = tmp;
	return low;//low代表找到的基准的位置
}


void BubbleSort(int *arr, int len)
{
	for (int i = 0; i < len - 1; i++)//趟数
	{
		bool swap = false;//swap用来判断是否已经有序(冒泡法的优化)
		for (int j = 0; j < len - 1 - i; j++)
		{
			int tmp = 0;
			if (arr[j] > arr[j + 1])
			{
				tmp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = tmp;
				swap = true;
			}
		}
		if (!swap)//swap == false//如果已经有序则跳出循环,不再进行比较。
		{
			break;
		}
	}
}

时间复杂度:
无序:O( n 2 n^2 )
有序:O( n n )

空间复杂度:O( 1 1 )

稳定性:稳定

选择排序

选择排序思路如下:

从待排序数字开始,后面找到比待排序数字小的数字就发生交换,一直到整个序列遍历完。

代码如下:

void SelectSort(int *arr, int len)
{
	for (int i = 0; i < len; i++)
	{
		for (int j = i + 1; j < len; j++)
		{
			if (arr[j] < arr[i])
			{
				int tmp = arr[j];
				arr[j] = arr[i];
				arr[i] = tmp;
			}
		}
	}
}


时间复杂度:
有序:O( n 2 n^2 )
无序:O( n 2 n^2 )

空间复杂度:O( 1 1 )

稳定性:不稳定

直接插入排序

直接插入排序思路如下:

如果有如下一组数字:4,2,6,5,3 首先当我们在最开始的时候,4 是
有序的,然后当拿到数据 2 时,我们需要把 2 放到 4 之前,那也就是
说,我们需要让 4 往后移,然后插入 2,以此类推,我们每次在移动
的时候,是比较一个数字,移动一个数字,并且是从后往前移动。

代码如下:

void InsertSort(int *arr, int len)
{
	for (int i = 1; i < len; i++)
	{
		int tmp = arr[i];
		int j = 0;
		for (j = i - 1; j >= 0; j--)
		{
			if (arr[j] > tmp)
			{
				arr[j + 1] = arr[j];
			}
			else
			{
				break;//如果找到要插进去的位置,跳出内层循环
			}
		}
		arr[j + 1] = tmp;
	}
}


时间复杂度:
有序:O(n) 越有序 越快
无序:O( n 2 n^2 )

空间复杂度:O(1)

稳定性:稳定排序

希尔排序

希尔排序思路如下:

  • 采用分组的思想,把一组数字分为若干的小组。
  • 而在分组的过程当中,并不是几个几个紧挨着的分组,而是采用特定的
    分组方式,每一次都让组内有序。
  • 这样排序的好处是,每次排序都是将小的数据尽量往前赶,大的数据尽量往后
    赶。
  • 在这里面,每一组的数字个数,在每一次分组的时候, 都会缩小增量,比如第一次分组每组 3 个,第二次每组 5 个, 第三次每组 1 个这样去分。(最后一次就直接进行一次插入排序)
  • 优点在于,如果不执行前面的分组过程的话,数据的移动次数更多,更复杂,经过排序之后,数据已经越来越有序了,利用直接插入排序特性(越有序越快)

代码如下:

void Shell(int *arr, int len, int gap)//组内进行直接排序
{
	for (int i = gap; i < len; i++)
	{
		int tmp = arr[i];
		int j = 0;
		for (j = i - gap; j >= 0; j = j - gap)
		{
			if (arr[j] > tmp)
			{
				arr[j + gap] = arr[j];
			}
			else
			{
				break;
			}
		}
		arr[j + gap] = tmp;
	}
}



void ShellSort(int *arr, int len)
{
	int drr[] = { 5,3,1 };//每次的分组长度
	int lend = sizeof(drr) / sizeof(drr[0]);
	for (int i = 0; i < lend; i++)
	{
		Shell(arr, len, drr[i]);
	}
}


时间复杂度:与增量数组有关

空间复杂度: O(1)

稳定性:不稳定

好的增量序列的共同特征:
1、 最后一个增量必须为 1;
2、应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。

猜你喜欢

转载自blog.csdn.net/qq_43313035/article/details/84132151
今日推荐