数据结构 之 七大排序 (持续更新ing...)

         下面算法编写的均是按照由小到大顺序进行排序版本


选择排序

思想:

        每次遍历待排序元素的最大下标,与待排序元素中最后一个元素交换位置(此时需要设置一个临时变量来存放下标)

  • 时间复杂度--O(n^2)
  • 空间复杂度--O(1)
  • 稳定性--不稳定

代码实现

#include<iostream>
using namespace std;
const int N = 1e2 + 10;
int num[N];
int n;

void select_sort()
{
	for (int i = 1; i < n; i++)//控制找最大值的次数
	{
		int index = 1;//存待排序元素的最小元素的下标
		for (int j = 1; j <= n - i; j++)
		{
			if (num[index] < num[j])
				index = j;
		}
		swap(num[index],num[n-i]);
	}
}
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> num[i];
	}
	select_sort();
	for (int i = 1; i <= n; i++) cout << num[i] << " " << endl;
}


冒泡排序 

思想:

        相邻两个元素比较,前一个比后一个大则交换

(每遍历一次都会冒出最大值 每次遍历最后一个一定是最大的)

  • 时间复杂度--O(n^2)  (逆序时达到O(n^2))
  • 空间复杂度O(--1)
  • 稳定性--稳定

优化:

        当整个数组遍历过程中没有发生交换,说明待排序数组已经有序,直接结束排序过程(bool类型变量做标记)

代码实现

#include <iostream>
using namespace std;
const int N = 1e2 + 10;
int num[N];
int n;

void bubble_sort()
{
    for (int i = 1; i < n; i++)
    {
        bool flag = false;
        for (int j = 1; j <= n - i; j++)
        {
            if (num[j] > num[j + 1])
            {
                swap(num[j], num[j + 1]);
                flag = true;
            }
        }
        if (!flag) break;
    }
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> num[i];
    }
    bubble_sort();
    for (int i = 1; i <= n; i++)
    {
        cout << num[i] << " ";
    }
    return 0;
}


计数排序(桶排序)

思想:

将数值作为桶号,遍历整个数组,将相应的桶进行计数
1、遍历原数组,找到最大值 max,然后申请max+1个空间(桶),初始化为0(下标为0-max),即vector<int>bucket(max+1,0)
2、再次遍历原数组,找到每个数值对应的桶号,并对桶计数++,即bucket[vec[i]++

3、遍历桶数组,看对应的桶内计数为几就取出几下下标值(桶号),放到原数组中。
 

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)
  • 稳定性:稳定

代码实现

#include<iostream>
using namespace std;

const int N = 1e4;
int num[N];
void Bucket_Sort(int n)
{
	//找待排序中的最大值
	int max = num[0];
	for (int i = 1; i < n; i++)
		max = max < num[i] ? num[i] : max;
	//创建桶
	int* bucket = new int[max + 1] {0};
	//将元素放入桶中
	for(int i=0;i<n;i++)
	bucket[num[i]]++;//计数
	//将元素取出还原
	int j = 0;
	for (int i = 1; i <= max; i++)
	{
		while (bucket[i] > 0)
		{
			num[j++] = i;
			bucket[i]--;
		}
	}
}
int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> num[i];
	}
	Bucket_Sort(n);
	for (int i = 0; i < n; i++)
	{
		cout << num[i] << " ";
	}
	return 0;
}

插入排序

思想:

        有序部分设置1个元素 无序部分设置n-1个元素,无序一个一个插入有序中。外层循环控制插入元素的个数(n-1) 内层找位置插入哪

  • 时间复杂度 :O(n^2)
  • 空间复杂度:O(1)
  • 稳定性:稳定

代码实现

#include<iostream>
using namespace std;
void Insert_sort(int a[], int n)
{
    for (int i = 1; i < n; i++)//控制插入元素的个数
    {
        int temp = a[i];//记录插入元素
        int j = i - 1;//记录有序表中最后一个元素
        for (; j >= 0; j--)
        {
            if (a[j] > temp)
                a[j + 1] = a[j];
            else
                break;
        }
        a[j + 1] = temp;
    }
}

int main()
{
    int a[6] = { 2,1,5,3,4,0 };
    Insert_sort(a, 6);
    for (int i = 0; i < 6; i++)
    {
        cout << a[i] << " ";
    }
        return 0;
}

堆排序 

思想:将待排序数组想象成一个最大堆结构,从最后一个有子节点的根节点开始调整,即最后一个父亲节点的下标(n/2-1),(若父亲节点的坐标为i,则其左孩子的下标是2i+1,右孩子下标是2i+2)

原理

        1.完全二叉树:若树的深度为h,除第h层以外,其余各层(1~h-1)的节点数达到最大个数,第h层所有的节点都连续集中在最左边,只能从最深处右边从右往左缺省。

        2.最大堆结构:是一个完全二叉树,堆中每个节点的值总是不大于其父亲节点的值(每颗子树上根节点最大,整棵树根节点最大)

        3.创建最大堆结构:把所有非终端节点检查一遍,看是否满足最大堆的要求,若不满足,则进行调整(检查当前节点是否满足:根>=左、右,若有不满足,则当前节点与更大的一个人孩子节点进行交换,若元素互换破坏了下一级的堆,则采用相同的方式继续调整,直至符合最大堆要求,我们以数组{53,27,78,9,45,65,87,32}为例.

(二叉树的终端节点:度为零的节点,就是叶子节点)

  • 时间复杂度:O(nlog2 n)
  • 空间复杂度:O(1)
  • 稳定性:不稳定
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

void adjustHeap(vector<int>& vec, int start, int end)
{
	int father = start;//根节点
	int child = father * 2 + 1;//左子树
	while (child <= end)//循环是为了再调整最大堆的过程中破坏子树的结结构,继续向下调整 
	{
		//因为child是左子树,根节点要大于左右子树,所以要在子树中找到最大的再与根节点进行比较,
		//所以要防止右子树越界就是在数组下标为child+1的元素,child就是子树中最大的元素 
		if (child + 1 <= end && vec[child + 1] > vec[child])
			child++;
		if (vec[child] > vec[father])//如果根节点小于子树就交换 
		{
			swap(vec[child], vec[father]);
			//如果发生交换继续向下调整,因为可能破环子树的最大堆结构
			father = child;
			child = 2 * father + 1;
		}
		//如果没有发生交换就退出该函数
		else
			return;
	}
}
void HeapSort(vector<int>& vec)
{
	//从最后一个有子节点的节点开始调整
    //O(n)
	for (int i = vec.size() / 2 - 1; i >= 0; i--)//vec.size()/2是完全二叉树最后一个有子节点的节点 
	{
		adjustHeap(vec, i, vec.size() - 1);
	}
    //O(nlog2 n)
	for (int i = vec.size() - 1; i >= 1; i--)
	{
		swap(vec[0], vec[i]);
		//只有下表为为0的元素被打乱,从根节点开始向下调整
		adjustHeap(vec, 0, i - 1);
	}
}
int main()
{
	vector<int>vec = { 53,17,78,9,45,65,87,32 };
	HeapSort(vec);
	for (auto it : vec)
	{
		cout << it << " ";
	}
	return 0;
}


        如果你对探索机器学习的无限可能性、掌握Python编程的技巧、以及玩转各种框架的技能充满了好奇心,那么恭喜你,你来对地方了!赶紧扫描下方二维码,加入我们的微信公众号吧!这里有最新的技术趋势、独家教程、精彩案例等着你,让我们一起探索未知的领域,开启编程之旅吧!🚀🌟

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

了一li

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值