插入排序,归并排序,选择排序,二分查找算法,冒泡排序

目录

一.插入排序

二.归并排序

三.选择排序

四.二分查找算法

五.冒泡排序


一.插入排序

#include<iostream>
using namespace std;

//插入排序思路:默认数组的第一个元素是按顺序排序的,从第二个元素开始,设置一个key值依次保存每个元素并与此元素之前的元素进行比较,直到找到其在数组中合适的位置。
void insertion_sort(int arr[], int n) //按升序排序
{
	int key;
	int j;
	for (int i = 1; i < n; i++)
	{
		key = arr[i]; //用来插入的元素
		j = i - 1;//从第i个元素的上个元素开始比较
		while (j >= 0&&key<arr[j]) //key<arr[j]则说明这两个元素应当交换位置,且交换完后继续比较直到无需交换为止
		{
			//交换位置,然后更新j值继续比较
			arr[j + 1] = arr[j];
			arr[j] = key; //key = arr[i] = arr[j+1]
			j--;	
		}
	}
}

int main()
{
	int arr[5] = { 5,2,4,1,3 };
	cout << "排序前; " << endl;
	for (int i = 0; i < 5; i++)
	{
		cout << arr[i];
	}
	insertion_sort(arr, 5);
	cout << "排序后: " << endl;
	for (int i = 0; i < 5; i++)
	{
		cout << arr[i];
	}

	system("pause");
	return 0;
}

知识点:

1.插入排序算法的实现思路是:初始状态下,将待排序序列中的第一个元素看作是有序的子序列。从第二个元素开始,在不破坏子序列有序的前提下,将后续的每个元素插入到子序列中的适当位置。

2.具体实现:

① 从第一个元素开始,该元素可以认为已经被排序
② 取出下一个元素,在已经排序的元素序列中从后向前扫描
③ 如果该元素(已排序)大于新元素,将该元素移到下一位置
④ 重复步骤③,直到找到已排序的元素小于或者等于新元素的位置
⑤ 将新元素插入到该位置后
⑥ 重复步骤②~⑤

3.性能分析:

① 平均时间复杂度:O(N^2)

② 最差时间复杂度:O(N^2)

③ 空间复杂度:O(1)

二.归并排序

#include<iostream>
#include<limits.h> //INT_MAX表示正无穷 INT_MIN表示负无穷
#include<float.h> //DBL_MAX表示正无穷 DBL_MIN表示负无穷
#include<vector>
using namespace std;

void Merge(int arr[], int p, int q, int r) //归并排序采用分治策略,p,q,r分别为数组分割的三个端点
{
	//根据参数将原数组分割成两个子数组
	int n1 = q - p + 1;
	int n2 = r - q;
	//常规的array数组无法用变量来设置数组的长度
	//使用vector数组来实现
	vector<int>L1(n1+1); 
	vector<int>L2(n2+1);
	
	
	//使用new开辟堆空间实现
	//int* L1 = new int[n1+1];
	//int* L2 = new int[n2+1];

	//设置哨兵牌
	L1[n1] = INT_MAX;
	L2[n2] = INT_MAX;
	
	//数组分割
	for (int i = 0; i < n1; i++)
	{
		L1[i] = arr[p+i]; // 0,1,2,3....q
	}
	for (int i = 0; i < n2; i++)
	{
		L2[i] = arr[q+1+i]; //q+1,q+2,q+3....r
	}
	//合并过程
	int x = 0, y = 0;//两个子数组的标记参数
	//按递增序列排序
	for (int i = p; i <= r; i++)
	{
		//如果L1[x]<=L2[y],则将较小的L1[x]放入原数组中的相应位置,并更新此时x指示的L1数组的位置。
		if (L1[x] <= L2[y])
		{
			arr[i] = L1[x];
			x++;
		}
		else
		{
			arr[i] = L2[y];
			y++;
		}
	}

	//delete[]L1;
	//delete[]L2;
}

//递归代码
void Merge_sort1(int arr[], int low,int high)
{
	if (low < high)
	{
		int mid = (low + high) / 2;
		Merge_sort1(arr, low, mid); //对low~mid段的数组进行进一步的细分
		Merge_sort1(arr, mid + 1, high); //对mid+1~high段的数组进行进一步的细分
		Merge(arr, low, mid, high); //递归中每次函数的调用均进行一次排序
	}
}

//非递归代码
void Merge_sort2(int arr[], int n) //n为数组中元素的个数,数组最大下表为n-1
{
	int size = 1, low, mid, high;
	while (size <= n - 1)
	{
		low = 0;
		while (low + size <= n - 1)
		{
			mid = low + size - 1;
			high = mid + size;
			if (high > n - 1)
			{
				high = n - 1;
			}
			Merge(arr, low, mid, high);
			low = high + 1;
		}
		size *= 2;
	}
}

int main()
{
	int arr[10] = {9,4,3,6,1,2,8,5,7,10};
	cout << "排序前: " << endl;
	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
	cout << "排序后: " << endl;
	Merge_sort1(arr, 0, 9);
	//Merge_sort2(arr, 10);
	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << " ";
	}

	system("pause");
	return 0;
}

知识点:

1.分治模式(归并算法完全遵循分治模式)

① 分解原问题为若干子问题,这些子问题是原问题的规模较小的实例

② 解决这些子问题,递归地求解各子问题。然而,若子问题的规模足够小,则直接求解

③ 合并这些子问题的解成原问题的解

2.归并算法的分治模式:

① 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列

② 解决:使用归并排序递归地排序两个子序列

③ 合并:合并两个已排序的子序列以产生已排序的答案

3.设置哨兵牌:给子数组多设置一个元素,并赋值给该元素无穷大的值以表示数组堆到底,保证后续比较元素并将数组合并的过程不会出现错误。

4.无穷大的表示:

① 如果是int,用INT_MAX表示正无穷,INT_MIN表示负无穷,需要包含头文件limits.h;

② 如果是double,用DBL_MAX表示正无穷,DBL_MIN表示负无穷,需要包含文件float.h。

5.性能分析:

① 平均时间复杂度:O(nlogn)
② 最佳时间复杂度:O(n)
③ 最差时间复杂度:O(nlogn)
④ 空间复杂度:O(n)

三.选择排序

//选择排序:首先找出数组中的最小元素与第一个元素交换,接着继续找出除第一个元素外的最小元素与第二个元素交换,重复该步骤。
#include<iostream>
#include<limits.h>;
using namespace std;


void Select_sort(int arr[], int n)
{
	//一共进行n-1轮交换
	for (int i = 0; i < n - 1; i++)
	{
		//每次大循环开始时都要更新标识变量min和slogan
		int min = INT_MAX;
		int slogan = 0;
		//每次大循环中均需要一个小循环找到最小值,且每次小循环找最小值所需扫描的元素递减
		for (int j=i; j < n; j++) //循环的初始值设置为i,即从数组的第i个位置开始向下寻找此时数组元素的最小值
		{
			if (arr[j] < min)
			{
				min = arr[j]; //找到此轮循环中数组中的最小值
				slogan = j; //保存最小值对应的数组的位置
			}
		}
		//交换最小值与大循环参数i对应的数组位置
		arr[slogan] = arr[i];
		arr[i] = min;
	}
}

int main()
{
	int arr[10] = { 4,6,1,9,10,2,5,3,7,8 };
	cout << "排序前:" << endl;
	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;

	cout << "排序后:" << endl;
	Select_sort(arr, 10);
	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << " ";
	}

	system("pause");
	return 0;
}

知识点:

1.基本思想:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

2.实现逻辑:

① 第一轮从下标为 0 到下标为 n-1 的元素中选取最小值,若小于第一个数,则交换
② 第二轮从下标为 1 到下标为 n-1 的元素中选取最小值,若小于第二个数,则交换
③ 依次类推下去……

3.性能分析:

① 平均时间复杂度:O(N^2)
② 最佳时间复杂度:O(N^2)
③ 最差时间复杂度:O(N^2)
④ 空间复杂度:O(1)

四.二分查找算法

#include<iostream>
using namespace std;

int binary_search(int arr[],int low,int high,int value)
{
	int mid = (low + high) / 2;
	//递归的出口一:
	if (low > high)
	{
		return -1;
	}
	//mid = (low + high) / 2;
	//递归的出口二:
	if (value == arr[mid])
	{
		return mid;
	}
	else if (value < arr[mid]) //说明value值处于数组的上半部分区域
	{
		//通过递归继续缩小范围搜索(在low~mid-1范内)
		binary_search(arr,low,mid-1,value);
	}
	else if (value > arr[mid]) //说明value值处于数组的下半部分区域
	{
		//通过递归继续缩小范围搜索(在mid+1~high范围内)
		binary_search(arr,mid + 1, high, value);
	}
	
}


int main()
{
	int arr[10] = { 1,3,4,9,11,15,18,21,29,34};
	int v;
	//利用二分查找算法在数组arr中搜索v值,如果有此值则输出该值在数组中的位置,如果没有此值则说明数组中不存在该值。
	cout << "输入v的值: " << endl;
	cin >> v;
	int l = binary_search(arr, 0, 9, v);
	if (l == 0 || l == -1)
	{
		cout << "v值在数组中不存在" << endl;
	}
	else
	{
		cout << "v值在数组中的位置为第" << l + 1 << "位" << endl;
	}

	
	system("pause");
	return 0;
}

知识点:

1.在有序序列中,使用二分查找算法搜索目标元素的核心思想是:不断地缩小搜索区域,降低查找目标元素的难度。 

2.实现思路:

① 初始状态下,将整个序列作为搜索区域(假设为 [B, E]);

② 找到搜索区域内的中间元素(假设所在位置为 M),和目标元素进行比对。如果相等,则搜索成功;如果中间元素大于目标元素,表明目标元素位于中间元素的左侧,将 [B, M-1] 作为新的搜素区域;反之,若中间元素小于目标元素,表明目标元素位于中间元素的右侧,将 [M+1, E] 作为新的搜素区域;

③ 重复执行第二步,直至找到目标元素。如果搜索区域无法再缩小,且区域内不包含任何元素,表明整个序列中没有目标元素,查找失败。

3.使用二分查找算法的前提:

① 数列有序

② 数列使用顺序存储结构(eg.数组)

4.使用递归时一定要设置出口

//递归的出口一:
if (low > high)
{
	return -1;
}
//递归的出口二:
if (value == arr[mid])
{
	return mid;
}

五.冒泡排序

#include<iostream>
using namespace std;

void bubble_sort(int arr[], int n)
{
	int temp;
	for (int i = 0; i < n; i++)
	{
		//每次大循环后数组的最后一个元素会是数组中最大的元素,因此下一次小循环中只需要比较到数组的倒数第二个元素即可
		for (int j = 0; j < n - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}

int main()
{
	int arr[5] = { 2,3,5,1,4 };
	cout << "排序前: " << endl;
	for (int i = 0; i < 5; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
	bubble_sort(arr, 5);
	cout << "排序后: " << endl;
	for (int i = 0; i < 5; i++)
	{
		cout << arr[i] << " ";
	}


	system("pause");
	return 0;
}

知识点:

1.冒泡排序(Bubble Sort) 最为简单的一种排序,通过重复走完数组的所有元素,通过打擂台的方式两个两个比较,直到没有数可以交换的时候结束这个数,再到下个数,直到整个数组排好顺序。因一个个浮出所以叫冒泡排序。双重循环时间 O(n^2)

2.实现思路:

① 比较相邻的元素。如果第一个比第二个大,就交换他们两个。

② 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。

③ 针对所有的元素重复以上的步骤,除了最后一个。

④ 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值