数据结构—选择、插入、冒泡排序

排序的分类  

  • 排序的分类:排序分为插入排序、选择排序、交换排序、归并排序四大类,详细分类如下图:

  •  七大经典排序:冒泡排序、快速排序、选择排序、堆排序、插入排序、希尔排序、归并排序

1.简单选择排序

1.1 基本思想

  • 每一趟 (例如第 i 趟,i = 0, 1, …, n-2)在后面 n-i 个待排的数据元素中选出关键字最小的元素,作为有序元素序列的第 i 个元素。

  • R[0..i]和R[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;

1.2 图示

1.3 代码实现

// 分类 -------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- O(n^2)
// 最优时间复杂度 ---- O(n^2)
// 平均时间复杂度 ---- O(n^2)
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 不稳定

#include <stdio.h>
#include <stdlib.h>

void println(int array[], int len)   
{
	int i = 0;

	for (i = 0; i < len; i++)
	{
		printf("%d ", array[i]);
	}

	printf("\n");

}

void swap(int array[], int i, int j)
{
	int temp = array[i];
	array[i] = array[j];
	array[j] = temp;
}

void SelectionSort(int array[], int len)  
{
	int i = 0;
	int j = 0;
	int k = -1;  // k用来标记最小元素的位置

	for (i = 0; i < len; i++)
	{
		k = i;

		for (j = i; j < len; j++)  // 最小值查找
		{
			if (array[j] < array[k])
			{
				k = j;
			}
		}

		swap(array, i, k);
	}
}

int main(int argc, char *argv[])
{
	int array[] = { 21,25,49,25,16,8 };
	int len = sizeof(array) / sizeof(*array);

	printf("选择排序前:");
	println(array, len);

	SelectionSort(array, len);

	printf("选择排序后:");
	println(array, len);

	system("pause");

	return 0;
}
  • 运行结果:
  • 选择排序是不稳定的排序算法,不稳定发生在最小元素与交换的时刻比如序列:{ 5, 8, 5, 2, 9 },一次选择的最小元素是2,然后把2和第一个5进行交换,从而改变了两个元素5的相对次序。

2.直接插入排序

  • 当插入第i (i\geq 1) 个数据元素时,前面的V[0], V[1], …, V[i-1]已经排好序。这时,用V[i]的关键字与V[i-1], V[i-2], …的关键字进行比较, 找到插入位置即将V[i]插入,原来位置上的对象向后顺移。

  • 初始的有序序列:任意一个元素都可以认为是有序的,将数组的第一个元素看作是有序序列

2.2 图示

2.3 代码实现

// 分类 ------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- 最坏情况为输入序列是降序排列的,此时时间复杂度O(n^2)
// 最优时间复杂度 ---- 最好情况为输入序列是升序排列的,此时时间复杂度O(n)
// 平均时间复杂度 ---- O(n^2)
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 稳定

#include <stdio.h>
#include <stdlib.h>

void println(int array[], int len)   
{
	int i = 0;

	for (i = 0; i < len; i++)
	{
		printf("%d ", array[i]);
	}

	printf("\n");

}

void InertionSort(int array[], int len) // O(n*n)  
{
	int i = 0;
	int j = 0;
	int k = -1;
	int temp = -1;

	for (i = 1; i < len; i++)
	{
		k = i;
		temp = array[k];

		for (j = i - 1; (j >= 0) && (array[j] > temp); j--)  // 有序序列
		{
			array[j + 1] = array[j];
			k = j;
		}

		array[k] = temp;
	}
}

int main(int argc, char *argv[])
{
	int array[] = { 21,25,49,25,16,8 };
	int len = sizeof(array) / sizeof(*array);

	printf("插入排序前:");
	println(array, len);

	InertionSort(array, len);

	printf("插入排序后:");
	println(array, len);

	system("pause");

	return 0;
}

运行结果: 

3.冒泡排序

3.1 基本思想

  • 设待排数据元素序列中的元素个数为n,最多作 n-1 趟,i = 1, 2,..., n-1。在第 i 趟中从后向前,j = n-1, n-2,..., i,两两比较V[j-1]和V[j]的关键字。如果发生逆序,则交换V[j-1]和V[j]。

3.2 图示

  • exchange表示是否发生交换

3.3 代码实现

// 分类 -------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- O(n^2)(逆序)
// 最优时间复杂度 ---- 如果能在内部循环第一次运行时,使用一个旗标来表示有无需要交换的可能,可以把最优时间复杂度降低到O(n)
// 平均时间复杂度 ---- O(n^2)
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 稳定

#include <stdio.h>
#include <stdlib.h>

void println(int array[], int len)
{
	int i = 0;

	for (i = 0; i < len; i++)
	{
		printf("%d ", array[i]);
	}

	printf("\n");
}

void swap(int array[], int i, int j)
{
	int temp = array[i];
	array[i] = array[j];
	array[j] = temp;
}

void BubbleSort(int array[], int len) // O(n*n)  
{
	int i = 0;
	int j = 0;
	int exchange = 1;

	for (i = 0; (i < len) && exchange; i++)
	{
		exchange = 0;  // exchange作优化,表示是否发生交换

		for (j = len - 1; j > i; j--)
		{
			if (array[j] < array[j - 1])
			{
				swap(array, j, j - 1);

				exchange = 1;
			}
		}
	}

	// printf("%d\n", i);   // 标记趟数
}

int main(int argc, char *argv[])
{
	int array[] = { 5,4,3,2,1 };
	int len = sizeof(array) / sizeof(*array);

	printf("冒泡排序前:");
	println(array, len);

	BubbleSort(array, len);

	printf("冒泡排序后:");
	println(array, len);

	system("pause");

	return 0;
}
  • 运行结果:

4.小结

  • 选择排序,插入排序以及冒泡排序的算法思想简单,且算法的时间复杂度同为O(n2)量级;
  • 插入和冒泡排序算法的结果是稳定的,而选择排序不稳定;
  • 注意选择排序与冒泡排序的区别:冒泡排序通过依次交换相邻两个顺序不合法的元素位置,从而将当前最小(大)元素放到合适的位置;而选择排序每遍历一次都记住了当前最小(大)元素的位置,最后仅需一次交换操作即可将其放到合适的位置。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值