面试准备之手写9种排序算法(默认从小到大排序)之插入排序、冒泡排序、选择排序、希尔排序

插入排序

第一重循环下标从1到n-1,一是表示插入轮数,而是为下一重循环nums[j]和nums[j - 1]比较并交换(nums[j]>nums[j-1]时)做准备,再有就是下一重循环是逆向进行,由于之前的下标在之前的循环中已经经排序是有序的了,只要有nums[j] >= nums[j - 1]的就直接退出循环即可。这里可能有点难懂,但要注意插入排序其实是逐个插入的操作,理解到这点就能明白二重循环退出条件的深意了。代码如下:

cpp 复制代码
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;

int main() {
	vector<int> nums;
	srand(time(0));
	for (int i = 0; i < 10; i++) 
		nums.push_back(rand());
	for (int i =0; i <nums.size(); i++)
		cout << nums[i] << ' ';
	cout << endl;
	for (int i = 1; i < nums.size(); i++) {
		for (int j = i; j > 0 && nums[j] < nums[j - 1]; j--) {
			int temp = nums[j];
			nums[j] = nums[j - 1];
			nums[j - 1] = temp;
		}
	}
	for (int i = 0; i < nums.size(); i++)
		cout << nums[i] << ' ';
}

冒泡排序

最基本的排序算法了。第一重循环表示次数上的循环,要总共冒泡nums.size() - 1次。第二重循环表示需要让nums[j]和nums[j+1]比较也是从0到nums.size() - 1的下标遍历。循环里面就比较并交换即可。

cpp 复制代码
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;

int main() {
	vector<int> nums;
	srand(time(0));
	for (int i = 0; i < 10; i++) 
		nums.push_back(rand());
	for (int i =0; i <nums.size(); i++)
		cout << nums[i] << ' ';
	cout << endl;
	for (int i = 0; i < nums.size() - 1; i++) {
		for (int j = 0; j < nums.size() - 1; j++) {
			if (nums[j] < num[j + 1]) {
				int temp = nums[j];
				nums[j] = nums[j - 1];
				nums[j - 1] = temp;	
			}
		}
	}
	for (int i = 0; i < nums.size(); i++)
		cout << nums[i] << ' ';
}

选择排序

每次选择一个第i小的数,放到数组第i个位置上。实现时先用一个一重循环(下标从0到n-1,表示要选择n-1次,剩下一个必然是最大就不用选了),表示比较次数,依次往后。第二层也是一个逆循环,j从n-1到i+1取值,用一个minindex将i的值赋给它,依次将该下标值和nums[j]比较,比nums[j]小的话就将他俩交换一下,这样从后往前也能保证最后nums[minindex]是minindex下标(其实也就是i,只不过为了形象化定义了一个变量罢了)往后的数中最小的那一个,这样我们排序的目的也就达到了。

cpp 复制代码
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;

int main() {
	vector<int> nums;
	srand(time(0));
	for (int i = 0; i < 10; i++) 
		nums.push_back(rand());
	for (int i =0; i <nums.size(); i++)
		cout << nums[i] << ' ';
	cout << endl;
	for (int i = 0; i < nums.size() - 1; i++) {
		int minindex = i;
		for (int j = nums.size() - 1; j > i; j--) {
			if (nums[j] < nums[minindex]) {
				int temp = nums[j];
				nums[j] = nums[minindex];
				nums[minindex] = temp;
			}
		}
	}
	for (int i = 0; i < nums.size(); i++)
		cout << nums[i] << ' ';
}

Shell排序

相当于插入排序的升级版,不过用到了二分的思想,每次分成n/i份,每份有i个元素,各份起始下标视为0,对应下标处互相交换即可,只不过间隔由原本的1变成了i。二重循环内就是被分成的每一份内的起始下标的遍历了。再在内层循环中调用一个insesort2函数,这个函数就是原先的插入函数间隔更换后的改写版。代码如下:

cpp 复制代码
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;

void insesort2(vector<int>& nums, int n, int incr) {
	for (int i = incr; i < n; i+=incr) {
		for (int j = i; j >= 0 && nums[j] < nums[j - incr]; j-= incr) {
			int temp = nums[j];
			nums[j] = nums[j - incr];
			nums[j - incr] = temp;
			cout << "swap" << nums[j - incr] << ' ' << nums[j] << endl;
		}
	}
}

int main() {
	vector<int> nums;
	srand(time(0));
	for (int i = 0; i < 10; i++) 
		nums.push_back(rand());
	for (int i =0; i <nums.size(); i++)
		cout << nums[i] << ' ';
	cout << endl;
	for (int i = nums.size() / 2; i > 2; i/=2) {
		for (int j = 0; j < i; j++) {
			insesort2(nums, nums.size(), i);
		}
	}
	insesort2(nums, nums.size(), 1);
	for (int i = 0; i < nums.size(); i++)
		cout << nums[i] << ' ';
}

需要注意的是insesort2中第二层循环要用到插入排序相关知识,需要理解清楚,尤其j初始值和判断条件中比0大这一条件应该弄清楚。

相关推荐
软工菜鸡25 分钟前
预训练语言模型BERT——PaddleNLP中的预训练模型
大数据·人工智能·深度学习·算法·语言模型·自然语言处理·bert
南宫生27 分钟前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
AI视觉网奇1 小时前
sklearn 安装使用笔记
人工智能·算法·sklearn
JingHongB1 小时前
代码随想录算法训练营Day55 | 图论理论基础、深度优先搜索理论基础、卡玛网 98.所有可达路径、797. 所有可能的路径、广度优先搜索理论基础
算法·深度优先·图论
weixin_432702261 小时前
代码随想录算法训练营第五十五天|图论理论基础
数据结构·python·算法·深度优先·图论
小冉在学习1 小时前
day52 图论章节刷题Part04(110.字符串接龙、105.有向图的完全可达性、106.岛屿的周长 )
算法·深度优先·图论
Repeat7151 小时前
图论基础--孤岛系列
算法·深度优先·广度优先·图论基础
小冉在学习1 小时前
day53 图论章节刷题Part05(并查集理论基础、寻找存在的路径)
java·算法·图论
武子康2 小时前
大数据-212 数据挖掘 机器学习理论 - 无监督学习算法 KMeans 基本原理 簇内误差平方和
大数据·人工智能·学习·算法·机器学习·数据挖掘
passer__jw7672 小时前
【LeetCode】【算法】283. 移动零
数据结构·算法·leetcode