排序

冒泡排序

1.虽然容易理解,但是容易TLE;
2.冒泡排序就是每次排序至少能将一个数放在它应该出现的位置,所以如果有n个元素,则需要n-1次排序;

冒泡排序_代码模板

#include<bits/stdc++.h>
using namespace std;
int n;
int arr[100000] = { 0 };
void maopao_sort(int arr[], int sz)
{
	for (int i = 0; i < sz - 1; i++)
	{
		for (int j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				swap(arr[j], arr[j + 1]);
			}
		}
	}
}
int main()
{
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &arr[i]);
	}
	maopao_sort(arr, n);
	for (int i = 0; i < n; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

快速排序

本质是分治,一般情况下在算法竞赛中很难用到(毕竟大部分排序题都是一个sort就能解决的问题),基本上只有面试官在面试时会让你手打;

快速排序_基本思路

1.选择中心轴pivot(我个人喜欢将pivot直接放在最左最右,但是可能刚好处理不了个数为100000的数组);
2.将大于pivot的值放在其右,小于的放在其左;
3.分别对pivot左右两子序列重复上述操作。

快速排序_操作步骤

1.为了方便,选取最左边的数字为中心轴pivot,并将其放在一边,并在原位置设定一个left指针,从左往右读取,在最右边设计一个right指针,从右往左读取;
例如下图,我们选择19为pivot,然后把19单独提出来,再把最左定为left(因为19被拿走了,所以这里left指向的是一个空数组),最右定为right

2.如果left发现比pivot大的数字,就把该数字放在right上,反之则不移动该数字,跳过right的当前回合,left读取下一位,right同left一样移动法则;
如下图

因为L为空,所以从R先开始,8<19,8挪到L的位置

R移动了数字,回合结束,L往前走一格

97>19,97挪到R位置,L回合结束

R往前走一格,1 < 19 , 1挪到L处

R回合结束,L往前走一格,9 < 19,符合条件,不挪动9

L获得一个额外的回合,17 < 19 , 17不动

L再获得一个额外的回合,再走一格,与R重合
3.最终,left和right会在该序列的某一处相遇,把pivot放在该位置,这就完成了第一次排序,后面再对左右子序列重复以上操作即可。如果有左或右子序列只有一个或无元素,则无需再对该序列进行排序;

快速排序_代码模板


#include<bits/stdc++.h>
using namespace std;
int n;
int arr[100005];

void quicksort(int arr[], int l, int r)
{
	if (l >= r)//判断没有或者是否只有一个元素
	{
		return;//说明该序列或左右子序列完成快排
	}
	int left = l;
	int right = r;
	int pivot = arr[left];//定中心轴
	while (left < right)//如果左比右小
	{
		while (left < right && arr[right] >= pivot)
		{
			right--;//右指针必须大于左指针下标,并且如果所代表数大于中心轴,则移动至下一位
		}
		if (left < right)//防止left = right特判被误判
		{
			arr[left] = arr[right];//把右边的数移动到左指针的位置
		}
		while (left < right && arr[left] <= pivot)//同理
		{
			left++;
		}
		if (left < right)
		{
			arr[right] = arr[left];
		}
	}
	if (left >= right)//在左右指针交合之处丢下中心轴
	{
		arr[left] = pivot;
	}

	quicksort(arr, l, right - 1);//对左右子序列不断进行快排
	quicksort(arr, left + 1, r);
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> arr[i];
	}
	quicksort(arr, 0, n - 1);
	for (int i = 0; i < n; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

归并排序_基本思路

1.先将序列中的每个数字单独设为一组;
2.再将每两个组合中的数字合并为一个组合,保证组合后的数字是有序的;
3.重复第二步,直到只剩下一组。

归并排序_具体步骤

1.将序列中的每个数字单独设为一组

2.两两合并,并保持有序


3.再将得到的组合再次两两合并


4.继续两两合并

归并排序_代码模板

#include<bits/stdc++.h>
using namespace std;
const int N = 100000;
int n;
int arr[N] = { 0 };
int tmp[N];

void merge_sort(int arr[], int l, int r)
{
	if (l >= r)//左右指针重合,返回
	{
		return;
	}
	int mid = (l + r) / 2;
	merge_sort(arr, l, mid);//递归排序左边
	merge_sort(arr, mid + 1, r);//递归排序右边
	//以下归并,把结果放入tmp
	int k = 0;
	int i = l, j = mid + 1;//i为左边最开始点,j为右边最开始点;
	while (i <= mid && j <= r)//当左半边和右半边都没有循环空的话;
	{
		if (arr[i] <= arr[j])
		{
			tmp[k++] = arr[i++];//把每一个小的放在我们当前位置上去;
		}
		else
		{
			tmp[k++] = arr[j++];
		}
	}
	while (i <= mid)//这两个while是如果有一边没有循环完的话,直接接入答案;
	{
		tmp[k++] = arr[i++];
	}
	while (j <= r)
	{
		tmp[k++] = arr[j++];
	}
	for (i = l, j = 0; i <= r; i++, j++)
	{
		arr[i] = tmp[j];//把存在tmp的结果赋值回arr;
	}
}

int main()
{
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &arr[i]);
	}
	merge_sort(arr, 0, n - 1);
	for (int i = 0; i < n; i++)
	{
		printf("%d ", arr[i]);
	}



	return 0;
}

sort

唯一真神

sort相关模板

sort(a + 0 , a + n);//从a[0]拍到a[n - 1];
is_sorted(a + 0  , a + n);//判断从a[0]到a[n - 1]是否为升序,若为升序,返回true;否则返回false
#include<bits/stdc++.h>
using namespace std;
int n;
int a[100005];
int main()
{
    cin >> n;
    for(int i = 0 ; i < n  ;i++)
    {
        cin >> a[i];
    }
    int *p = is_sorted_until(a , a + n);
    cout << p - a << endl;//有p - a个数字遵循升序排列(要从下标0开始排为最好);
    cout << *p << endl;//*p直接表示那个数字打断了排列,如果没有打断的,会返回0;
    
    return 0;
}
posted @ 2022-06-20 11:33  Zilliax  阅读(68)  评论(0)    收藏  举报