IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 自学笔记----------------十大排序算法(C++版) -> 正文阅读

[数据结构与算法]自学笔记----------------十大排序算法(C++版)

序言:swap函数的源代码

template<class T>
void swap(T &a,T &b){
	T temp = a;
	a = b;
	b =temp;
}

一、冒泡排序

算法:
1、比较相邻的元素,如果前一个大于后一个,则交换这两个数。
2、比较每一对相邻元素,从开始的第一对到最后一对
例: 3 5 2 4 1 6 -> 3 5 2 4 1 6 -> 3 2 5 4 1 6 -> 3 2 4 5 1 6 -> 3 2 4 1 5 6 -> 3 2 4 1 5 6
平均时间复杂度: O(N2)
空间复杂度: O(1)
稳定

冒泡次数        冒泡结果       交换轮数     检查轮数
原始数据      4 5 6 3 2 1        01次冒泡     4 5 3 2 1 6        3         52次冒泡     4 3 2 1 5 6        3         43次冒泡     3 2 1 4 5 6        3         34次冒泡     2 1 3 4 5 6        2         25次冒泡     1 2 3 4 5 6        1         1

代码实现:

//冒泡排序
void bubbleSort(vector<int>&nums) {
	
	int n = nums.size();
	if (n <= 1) return;
	bool flag = false;
	//下标从0开始  但是从下标1开始交换
	for (int i = 1; i < n ; i++) {
		//1 2 3 4 5 ... n-1     有n-1个数可与下一个数交换
		//i= 1  j= 1,2,...n-1   i之前的数不需要交换,i之后的交换
		for (int j = 1; j < n - i + 1; j++) {
			
			if (nums[j] < nums[j - 1]) {
				swap(nums[j], nums[j - 1]);
				flag = true;  //表示有数据交换
			}
		}
		if (!flag) break;   //没有数据交集,提前退出
	}
}

二、选择排序

算法:
每次从未排序的区间区间中找到最小的元素,将其放到已排序区间的末尾
平均时间复杂度: O(N2)
空间复杂度: O(1)
不稳定

//选择排序
void selectSort(vector<int>&nums) {
	int n = nums.size();
	if (n <= 1) return;
	//快慢指针
	for (int i = 0; i < n - 1; i++) {
		int tmp = i;
		for (int j = i + 1; j < n; j++) {
			if (nums[j] < nums[tmp])   tmp = j; //找出最小数的下标
		}
		swap(nums[tmp], nums[i]);
	}
}

三、插入排序

算法:
从数组第一个元素开始(初始已排序区间只有一个元素),遍历未排序的每一个元素,插入到已排序的区间保证数据有序。
平均时间复杂度: O(N2)
空间复杂度: O(1)
稳定

代码实现:

//插入排序
void insertSort(vector<int>&nums) {
	int n = nums.size();
	if (n <= 1) return;
	//双指针  对已排序的数进行插入
	for (int i = 0; i < n; i++) {
		for (int j = i; j > 0; j--) {
			if (nums[j] < nums[j - 1]) {	
				swap(nums[j], nums[j - 1]);
			}
		}
	}
}

四、希尔排序

算法:
将比较的全部元素取越来越小的步长,分几个区域排序
平均时间复杂度: O(Nlog2N)
空间复杂度: O(1)
不稳定

//希尔排序
void shellSort(vector<int>&nums) {
	int n = nums.size();
	if (n <= 1) return;
	//取步长
	for (int gap = n / 2; gap > 0; gap /= 2) {
		for (int i = gap; i < n; i++) {
			for (int j = i; j - gap >= 0; j -= gap) {
				if (nums[j] < nums[j - gap]) {
					swap(nums[j - gap], nums[j]);
				}
			}
		}
	}
}

五、归并排序

算法:
将全部元素分半分组,每一组再分半分组,递归下去,两两比较,再逐步合并到临时数组,最后全部排序
平均时间复杂度: O(NlogN)
空间复杂度: O(N)
稳定

//归并排序
void merge(vector<int>&nums, int left, int mid, int right) {
	int n = nums.size();
	//临时数组 必须规定容量n
	vector<int>temp(n);
	int i = left, j = mid + 1;//被分割的两个数组的起点下标
	int k = 0;//临时数组的下标
	while(i <= mid && j <= right) {
		if (nums[i] < nums[j])  temp[k++] = nums[i++];
		else temp[k++] = nums[j++];
	}
	//将剩余数据全部放入
	while (i <= mid) temp[k++] = nums[i++];
	while (j <= right) temp[k++] = nums[j++];


	//将临时数组中元素全部拷贝回原数组   
	for (int m = 0; m < k; m++) nums[left + m] = temp[m];

}
void mergeSort(vector<int>&nums,int left,int right) {
	if (left >= right) return;
	int mid = left + (right - left) / 2;

	//分治 递归
	mergeSort(nums, left, mid);
	mergeSort(nums, mid + 1, right);

	merge(nums, left, mid, right);//合并
}

六、快速排序

算法:
确定一个枢纽pivot,将所有其他元素跟pivot比较,较小的在前,较大的在后
平均时间复杂度: O(NlogN)
空间复杂度: O(logN)
不稳定

//快速排序
void quickSort(vector<int>&nums, int left, int right) {
	if (left >= right) return;
	
	//双指针
	int i = left, j = right;
	int pivot = nums[i];
	while (i < j) {
		//右指针 从右往左  小于pivot的值放左边
		while (i < j&&nums[j] >= pivot) j--;
		nums[i] = nums[j];
		//左指针 从左往右  大于pivot的值放右边
		while (i < j&&nums[i] <= pivot) i++;
		nums[j] = nums[i];
	}
	//更新
	nums[i] = pivot;
	//以nums[i]为界  分治  递归
	quickSort(nums, left, i - 1);
	quickSort(nums, i + 1, right);
}

七、堆排序

算法:
利用大根堆或小根堆的特性
ps:一般用到堆排序的算法,只需要priority_queue实现即可,这里不讨论堆排序本身实现的算法,讨论一下利用堆的特性实现排序的方法。
平均时间复杂度: O(NlogN)
空间复杂度: O(1)
不稳定

定义:priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆

1.基本类型

//对于基础类型 默认是大顶堆
    priority_queue<int> a; 
    //等同于 priority_queue<int, vector<int>, less<int> > a;
     priority_queue<int, vector<int>, greater<int> > c;  //这样就是小顶堆

2.pair的比较,先比较第一个元素,第一个相等比较第二个

priority_queue<pair<int, int> > a;

3.自定义类型

//方法1
struct tmp1 //运算符重载<
{
    int x;
    tmp1(int a) {x = a;}
    bool operator<(const tmp1& a) const
    {
        return x < a.x; //大顶堆
    }
};

//方法2
struct tmp2 //重写仿函数
{
    bool operator() (tmp1 a, tmp1 b) 
    {
        return a.x < b.x; //大顶堆
    }
};
priority_queue<tmp1> d;
priority_queue<tmp1, vector<tmp1>, tmp2> f;

八、计数排序

算法:
用待排序的数作为计数组的下标,统计每个数字的个数
平均时间复杂度: O(N2)
空间复杂度: O(1)
稳定

//计数排序
void countSort(vector<int>&nums) {
	int n = nums.size();
	if (n <= 1) return;

	int maxValue = nums[0];
	//找出最大值
	for (int i = 1; i < n; i++) {
		maxValue = max(maxValue, nums[i]);
	}

	//哈希表
	vector<int>tmp1(n + 1);
	for (int i = 0; i < n; i++) {
		tmp1[nums[i]]++;//统计每个数字的个数
	}
	//将所有数字分为 1~maxValue
	for (int i = 1; i <= maxValue; i++) {
		tmp1[i] += tmp1[i - 1];
	}
	vector<int>tmp2(n + 1);
	for (int i = n - 1; i >= 0; i--) {
		int idx = tmp1[nums[i]] - 1;
		tmp2[idx] = nums[i];
		tmp1[nums[i]]--;
	}

	for (int i = 0; i < n; i++) {
		nums[i] = tmp2[i];
	}
}

九、桶排序

算法:
将数组分到有限数量的桶里,每个桶再分别排序(个人理解,找出最大或者最小元素后,以序号的方式放桶,主要存储相同元素,最后大小输出直接按照序号输出)
平均时间复杂度: O(N+K)
空间复杂度: O(N+K)
稳定

//桶排序
void bucketSort(vector<int>&nums) {
	int len = nums.size();
	if (len <= 1) return;

	int low = *min_element(nums.begin(), nums.end());//最小元素
	int high = *max_element(nums.begin(), nums.end());//最大元素
	int n = high - low + 1;
	vector<int>buckets(n);//放置的桶
	vector<int>ans;

	for (auto x : nums) buckets[x - low]++;//相同的数放一个桶
	//按照序号输出
	for (int i = 0; i < n; i++) {
		//将相同的数输出
		for (int j = 0; j < buckets[i]; j++) {
			ans.push_back(i + low);
		}
	}
	for (int i = 0; i < ans.size(); i++) {
		nums[i] = ans[i];
	}
}

十、基数排序

算法:
对排序的数据有要求,需要可以分割出独立的“位”来比较,而且位之间有递进的关系,如果a的高位>b的高位,则a>b。此外,每一位的数据范围不能太大,需要一定线性,基数排序相当于循环多次实现多次桶排序。
ps:由于对数据有要求,加上时间空间复杂度并没有优于桶排序,这里不作深入研究。
平均时间复杂度: O(N×K)
空间复杂度: O(N+K)
稳定

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-09-21 00:52:38  更:2022-09-21 00:57:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 12:41:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码