1,冒泡
遍历第i次时,找出当前数组的最i大值.
如何找出:不断和周边进行比较,大的上升,所以有冒泡的概念.
2,插入
遍历到第i个数字的时候,将当前数字和之前i-1个已近排序的进行比较,插入到第一个比当前数字大的数字前面.所以叫做插入排序
3,希尔
希尔排序是插入排序的延伸,插入排序的gap固定为1,希尔排序gap是1/2缩减.两个放在一起记忆.
4,选择
依然是遍历选择最小的与第一个数字交换位置,选择第二小的与第二个数字交换位置.当考虑到位置的时候index是不错的选择
5,快速
快排的概念是选择一个base,base当前所处位置为i,要做到比base小的都在左面,比base大的都在右面. base最终会在k位置。步遍历所在数组,从left->right的过程中遇到比base 大的与从right->left中遇到比base小的,两个数字互换.
6,归并
分治法.分和治,将数组逐步拆分,最终变成一个个只有一个元素的单数组。然后merge,对于merge可以参考成,将两个有序数组合并成一个长的有序数组. 遗留(单独写一个函数)
7,桶(哈希表和优先队列)
**冒泡排序**
/*
冒泡排序:递增
思路:
从左到右依次遍历,第一次遍历找到整个数组最小的number, 第二次找到第二小的....遍历N轮下来, 实现递增
*/
void BubbleSort(vector<int>&nums, int n) {
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (nums[j] < nums[i]) {
swap(nums[i], nums[j]);
}
}
}
}
**插入排序**
/*
插入排序(希尔排序的延伸)
思路:
每次将一个待排序的数字/单位, 按照关键字的大小插入到已近拍好的子序列/文件中,直至全部记录已经插入完成为止.
常见的有插入排序, 希尔排序, 二叉树查找排序, 图书馆排序.
进一步解释:就像打扑克,新牌会逐渐与旧牌比对,插在第一个大于key的前面。
https://www.cnblogs.com/clc2008/p/6847780.html
比如:
step1:{12, 15, 9, 20, 6, 31, 24} 原有数组
step2:[12], 15, 9, 20, 6, 31, 24
step3:[12, 15 ], 9, 20, 6, 31, 24
step4:[9,12, 15 ], 20, 6, 31, 24
....
*/
void InsertSort(vector<int>&nums, int n)
{
for (int j = 1; j < n; j++) {
int key = nums[j]; // 待排序的第一个元素
int i = j - 1; // 表示已经排序的最后一个元素
while(i >= 0 && key < nums[i]) {
nums[i+1] = nums[i]; // 从后向前逐个比较key与已经排过序的数字的比较,如果比它小,当前字符向后移动一位
i--;
}
nums[i+1] = key;
}
}
**希尔排序**
希尔排序
希尔排序
/*
希尔排序:
思路:与插入排序类似,不同之处在于,会优先比较距离较远的元素,缩小增量排序.
先取一个小于len的整数d1作为第一个增量, 将文件全部分为d1个组,每个组len/d1个元素.因此每个的间隔都是d1[i, i + d1].
第一个组[1, 1 + d1]
第二个组[2, 2 + d1]
在各个组内部进行插入排序(当前数字逐个和前面的数字比较,插入到第一个比它大的数字中, 所以插入排序的前提就是前面是有序数组)
然后取步长d2, 再将数组分成d2个组, 每个组len/d2个元素.因此每个的间隔都是d2[i, i + d2, i + 2d2]
插入排序
step1:取步长
step2:插入排序
*/
void ShellSort(vector<int> &nums, int len)
{
int i, j, gap;
for (int gap = len / 2; gap > 0; gap /= 2) {
// 一共有gap个组
for (int i = 0; i < len; i++) {
for (int j = i + gap; j < len; j += gap) {
// 进行插入排序, j是当前值, 不断的插入之前的原有队列中
if(nums[j] >= nums[i]) { // 说明是希望从大到小排列
continue;
}
int tmp = nums[j];
int k = j - gap;
while(k >= 0 && nums[k] < tmp) {
nums[k+gap] = nums[k];
k-=gap;
}
nums[k + gap] = tmp;
}
}
}
}
**选择排序**
/*
选择排序(从小到大)
思路:从头到尾遍历,选择最小的数字与第一个数字互换位置,然后再遍历,选择第二小的与第二个遍历.
从左到右遍历数组, 选择最小的数字与第一个数字互换位置, 选择第二小的数字与第二个数字互换位置.....是一个选择的过程.
*/
void SelectSort(vector<int>&nums, int n)
{
for (int i = 0; i < n; i++) {
int minIndex = i; // 这是很巧的一点, 使用了index而不是直接使用minNum. 方便后面的互换.
for (int j = i + 1; j < n; j++) {
if (nums[j] < nums[minIndex]) {
minIndex = j;
}
}
swap(nums[i], nums[minIndex]);
}
}
**快速排序**
/*
快速排序
思路:
遍历nums到i,达到一个目标,nums[i]最终会放在k位置
int base = nums[i];
k左面的都是小于base, k右面的都是大于base,
从left向右遍历,遇到大于base,
从right向左遍历,遇到小于base和上面的交换位置。while的条件是left<=right
然后base放在left=right的k位置。
递归QuickSort(nums, left + 1, k)
QuickSort(nums, k, right-1)
*/
//快速排序(从小到大)
void quickSort(int left, int right, vector<int>& arr)
{
if(left >= right)
return;
int i, j, base, temp;
i = left, j = right;
base = arr[left]; //取最左边的数为基准数
while (i < j)
{
while (arr[j] >= base && i < j)
j--;
while (arr[i] <= base && i < j)
i++;
if(i < j)
{
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
//基准数归位
arr[left] = arr[i];
arr[i] = base;
quickSort(left, i - 1, arr);//递归左边
quickSort(i + 1, right, arr);//递归右边
}
**归并排序**
/*
归并排序
思路:归并排序是建立在归并操作上的一种算法, 对序列中的元素进行逐层对半, 然后从最小分组开始比较排序, 合并成一个大的分组, 逐层进行,最终所有的元素都是有序的. 所以有两个操作, 分裂+排序.
归并排序采用的是分治法.(divide and conquer)
将两个有序数列合并:
比较两个数列的第一个数, 谁小取谁, 若有数列为空, 直接将另一个数列中的数据依次取出即可.
// 在写归并排序之前先写一下将两个有序数组AB合并到C中. 可以参考下面的Merge.
如何从上面的排序中推到出归并排序呢,将数组拆分成A和B两个数组,然后再将AB内部各自划分成两个数组,当分出来的小组内部只有一个数据的时候,认为小组内部已经达到了有序,然后合并相邻的两个数组。
这样就可以通过递归的分解数列,合并数列完成了归并排序
*/
第一步:建立新的数组,其大小为两个已经排序序列之和,用来存放合并后的序列。
第二步:设定两个index分别为两个已经排序序列的起始位置。firstIndex和secondIndex
第三步:比较两个index所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置。
重复步骤三,直到某一指针超出序列尾。
第四步:将另一序列剩下的所有元素直接复制到合并序列尾部
```cpp
#include <iostream>
#include <String>
#include <string.h>
#include <vector>
#include <stack>
using namespace std;
void Merge(vector<int> &numbers, int start, int mid, int end) {
vector<int> temp(end - start + 1, 0);//第一步,申请空间,大小为两个排序序列之和
int fistSectionIndex = start; //第二步,设定两个待排序列的起始位置的索引
int secondSectionIndex = mid + 1;
int tempIndex = 0; //所申请空间的索引
while (fistSectionIndex <= mid && secondSectionIndex <= end) { //直到两个序列中有一个到达终止位置
if (numbers[fistSectionIndex] <= numbers[secondSectionIndex])
temp[tempIndex++] = numbers[fistSectionIndex++];
else
temp[tempIndex++] = numbers[secondSectionIndex++];
}
while (fistSectionIndex <= mid)
temp[tempIndex++] = numbers[fistSectionIndex++];
while (secondSectionIndex <= end)
temp[tempIndex++] = numbers[secondSectionIndex++];
for (int j = 0; j < tempIndex; ++j) //将合并且排序好的元素,复制到原来的数组中,释放临时数组空间
numbers[start + j] = temp[j];
}
void MergeSort(vector<int> &numbers, int start, int end) {
if (start >= end)
return;
int mid = (start + end) / 2;
MergeSort(numbers, start, mid); //递归排序numbers[start,mid](首先从上往下递归分解到最底层元素个数为1的情况)
MergeSort(numbers, mid + 1, end); //递归排序numbers[mid + 1,end](首先从上往下递归分解到最底层元素个数为1的情况)
Merge(numbers, start, mid, end); //然后递归的从下往上合并排序
}
int main() {
vector<int> nums{ 5,6,1,8,3,4,9,7,2,3 };
cout << "归并排序前:";
for (int i = 0; i < 10; i++)
cout << nums[i] << ' ';
cout << endl;
MergeSort(nums, 0, 9);
cout << "归并排序后:";
for (int i = 0; i < 10; i++)
cout << nums[i] << ' ';
cout << endl;
}
void Merge(vector&nums, int first, int mid, int last, vector temp)
{
int leftIndex = first;
int rightIndex = mid + 1;
int tempIndex = 0;
while (leftIndex <= mid && rightIndex <= last) {
if (nums[leftIndex] < nums[rightIndex]) {
temp[tempIndex++] = nums[leftIndex++];
} else {
temp[tempIndex++] = nums[rightIndex++];
}
}
while (leftIndex <= mid) {
temp[tempIndex++] = nums[leftIndex++];
}
while (rightIndex <= last) {
temp[tempIndex++] = nums[rightIndex++];
}
for (leftIndex = 0; leftIndex < tempIndex; leftIndex++) {
nums[first + leftIndex] = temp[leftIndex];
}
}
void Divide(vector&nums, int first, int last, vector&temp)
{
if (first >= last) {
return;
}
int mid = (first + last) / 2;
Divide(nums, first, mid, temp); //左边有序
Divide(nums, mid + 1, last, temp); //右边有序
Merge(nums, first, mid, last, temp); //再将二个有序数列合并
}
bool MergeSort(vector&nums, int n)
{
vector
**桶排序**
/*
桶排序
347. 前 K 个高频元素
思路:
使用哈希表来统计每个字符出现的个数, 然后就是如何找出top K的元素.
更希望把map值倒过来从<char, int> 变成<int, char>, 最好还是排序的, 所以想到了priority_queue
*/
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> map; //统计频次
for(auto i:nums) map[i]++;
priority_queue<pair<int,int>> que;
for(auto m:map){
que.push(make_pair(m.second, m.first)); //优先队列(堆)按照第一项进行排序
}
vector<int> vec;
for(int i=0;i<k;i++){
vec.push_back(que.top().second);
que.pop();
}
return vec;
}
};