九大算法基础简介
排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。用一张图概括:
关于时间复杂度
平方阶 (O(n2)) 排序 各类简单排序:直接插入、直接选择和冒泡排序。
线性对数阶 (O(nlog2n)) 排序 快速排序、堆排序和归并排序;
O(n1+§)) 排序,§ 是介于 0 和 1 之间的常数。 希尔排序
线性阶 (O(n)) 排序 基数排序,此外还有桶、箱排序。
关于稳定性
稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序。
不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序。
名词解释:
- n:数据规模
- k:"桶"的个数
- In-place:占用常数内存,不占用额外内存
- Out-place:占用额外内存
- 稳定性:排序后 2 个相等键值的顺序和排序之前它们的顺序相同
运行程序后各大算法效率对比
待排序的100个1到10000的数,排序30000次
各个算法源代码
mian函数:
冒泡排序
template<class T>
void BubbleSort(vector<T>& x)
{
bool flag = true;
for (unsigned i = 0; i < x.size() && flag; i++) {
flag = false;
for (unsigned k = 1; k < x.size(); k++) {
if (x[k] < x[k - 1]) {
T temp = x[k];
x[k] = x[k - 1];
x[k - 1] = temp;
flag = true;
}
}
}
}
选择排序
template<class T>
void SelectSort(vector<T>& x)
{
T temp;
for (unsigned i = 0; i < x.size(); i++) {
int minNumIndex = i;
for (unsigned k = i + 1; k < x.size(); k++) {
if (x[minNumIndex] > x[k]) {
minNumIndex = k;
}
}
if (minNumIndex != i) {
temp = x[minNumIndex];
x[minNumIndex] = x[i];
x[i] = temp;
}
}
}
插入排序
template<class T>
void InsertSort(vector<T>& x)
{
T temp;
for (unsigned i = 0; i < x.size(); i++) {
for (unsigned k = i + 1; k < x.size(); k++) {
if (x[i] > x[k]) {
temp = x[k];
x[k] = x[i];
unsigned p = i;
while (x[p] < temp && p>1) {
x[p] = x[p - 1];
}
x[p] = temp;
}
}
}
}
希尔排序
template<class T>
void ShellSort(vector<T>& x)
{
int Length = x.size();
for (int gap = Length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < Length; i++) {
T inserted = x[i];//此时待插入的数
int j;
for (j = i - gap; j >= 0 && inserted < x[j]; j -= gap) {
x[j + gap] = x[j];//将当前j位置的值移到gap后的位置
}
x[j + gap] = inserted;
}
}
}
计数排序
template<class T>
void ShellSort(vector<T>& x)
{
int Length = x.size();
for (int gap = Length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < Length; i++) {
T inserted = x[i];//此时待插入的数
int j;
for (j = i - gap; j >= 0 && inserted < x[j]; j -= gap) {
x[j + gap] = x[j];//将当前j位置的值移到gap后的位置
}
x[j + gap] = inserted;
}
}
}
基数排序
template<class T>
void RadixSort(vector<T>& x)
{
int* count = new int[10]; //计数器
int raidx = 1;
int k;
int index = 0;
vector<vector<T>>xArray;//创建十个容器
vector<T> xx;
for (int i = 0; i < 10; i++) {
xArray.push_back(xx);
}
//得到最大位数
T maxNum = x[0];
int weishu = 1;
for (int i = 1; i < x.size(); i++) {
if (maxNum < x[i]) { maxNum = x[i]; }
}
while (maxNum > 10) {
weishu++;
maxNum /= 10;
}
for (int j = 0; j < weishu; j++) {//进行weishu次排序
for (unsigned i = 0; i < x.size(); i++) {
k = (x[i] / raidx) % 10;//统计每个桶中的记录数
xArray[k].push_back(x[i]);
}
for (unsigned i = 0; i < xArray.size(); i++) {
for (unsigned p = 0; p < xArray[i].size(); p++) {
x[index] = xArray[i][p];//将是个容器中的值重新整合到 x中
index++;
}
}
for (unsigned i = 0; i < xArray.size(); i++) {
xArray[i].clear();
}
raidx *= 10;
index = 0;
}
}
二叉树排序
template<class T>
void BSTSort(vector<T>& x)
{
BST<int>bst(x);
x = bst.sortToVector();
}
二叉树源码:
#pragma once
#include<iostream>
#include<map>
#include <iomanip>
#include<queue>
using namespace std;
template<typename DataType>
class BST
{
private:
/**********数据成员*********/
class BinNode {
public:
DataType data;
BinNode* left;
BinNode* right;
BinNode() :left(0), right(0) {}//data默认初始化为DataType类型值,两条链为空
BinNode(DataType item) :data(item), left(0), right(right) {}//data初始化,其他两条链为空
};
typedef BinNode* BinNodePointer;
BinNodePointer myRoot;//根节点
void inorderAux(ostream& out, BST<DataType>::BinNodePointer subtreeptr)const;
void foreOrderAux(ostream& out, BST<DataType>::BinNodePointer subtreeptr)const;
void afterOrderAux(ostream& out, BST<DataType>::BinNodePointer subtreeptr)const;
void deleteAux(const DataType& item, bool& found, BST<DataType>::BinNodePointer& locptr, BST<DataType>::BinNodePointer& parent)const;
void BSTAux(BST<DataType>::BinNodePointer& ptr);
void horizontalGraphAux(ostream& out, int indent, BST<DataType>::BinNodePointer subtreeRoot)const;//打印
void verticalGraghAux(BST<DataType>::BinNodePointer ptr, vector<DataType>& elementVector)const;
void SortAux(BST<DataType>::BinNodePointer subtreeptr, vector<DataType>& v)const;//排序辅助函数
public:
/**********成员函数*********/
BST();
//构建空的BST
BST(vector<DataType>v);
~BST();//析构函数
bool empty();//判断BST是否为空,空则返回1
void add(const DataType& item);//节点的添加函数
void inorder(ostream& out)const;//中序输出
void foreorder(ostream& out)const;//前序输出
void afterOrder(ostream& out)const;//前序输出
void levelorder(ostream& out)const;//层次遍历输出
void Delete(const DataType& item);//删除节点
void graphHorizontal(ostream& out)const;//打印
void graphVertical(ostream& out)const;//打印
vector<DataType> sortToVector()const;//排序
};
template<typename DataType>
inline BST<DataType>::BST() :myRoot(0) {}
template<typename DataType>
inline BST<DataType>::BST(vector<DataType> v)
{
for (int i = 0; i < v.size(); i++) {
this->add(v[i]);
}
}
template<typename DataType>
inline BST<DataType>::~BST()
{
if (myRoot != 0) {
BSTAux(myRoot->left);
BSTAux(myRoot->right);
delete myRoot;
}
}
template<typename DataType>
bool inline BST<DataType>::empty()
{
return myRoot == 0;
}
template<typename DataType>
inline void BST<DataType>::add(const DataType& item)
{
BST<DataType>::BinNodePointer ptr = myRoot, parent = 0;
while (ptr != 0) {
parent = ptr;
if (item < ptr->data) {//下降到左子树
parent = ptr;
ptr = ptr->left;
}
else if (item >= ptr->data) {//下降到右子树
parent = ptr;
ptr = ptr->right;
}
}
ptr = new BST<DataType>::BinNode(item);
if (parent == 0) {
myRoot = ptr;
}
else if (item < parent->data) {
parent->left = ptr;
}
else {
parent->right = ptr;
}
}
template<typename DataType>
inline void BST<DataType>::inorder(ostream& out) const
{
cout << "中序遍历: ";
inorderAux(out, myRoot);
cout << endl;
}
template<typename DataType>
inline void BST<DataType>::foreorder(ostream& out) const
{
cout << "前序遍历: ";
foreOrderAux(out, myRoot);
cout << endl;
}
template<typename DataType>
inline void BST<DataType>::afterOrder(ostream& out) const
{
cout << "后序遍历: ";
afterOrderAux(out, myRoot);
cout << endl;
}
template<typename DataType>
inline void BST<DataType>::levelorder(ostream& out) const
{
queue<BST<DataType>::BinNodePointer>QueueOut;
queue<BST<DataType>::BinNodePointer>QueueStore;
QueueOut.push(myRoot);
QueueStore.push(myRoot);
while (!QueueStore.empty()) {
BST<DataType>::BinNodePointer localItem = QueueStore.front();
QueueStore.pop();
if (localItem->left != 0) {
QueueOut.push(localItem->left);
QueueStore.push(localItem->left);
}
if (localItem->right != 0) {
QueueOut.push(localItem->right);
QueueStore.push(localItem->right);
}
}
out << "层次遍历: ";
unsigned QueueOutSize = QueueOut.size();
for (unsigned i = 0; i < QueueOutSize; i++) {
out << QueueOut.front()->data << " ";
QueueOut.pop();
}
out << endl;
}
template<typename DataType>
inline void BST<DataType>::Delete(const DataType& item)
{
BST<DataType>::BinNodePointer parent, x = new BinNode();
bool found;
deleteAux(item, found, x, parent);//进行x 和 parent的赋值
if (!found) {
cout << "该节点没有被找到." << endl;
return;
}
else {
cout << "待删除的数: " << item << endl;
}
//节点有两个子女
if (x->left != 0 && x->right != 0) {
//查找x的中序后继 及双亲节点(右子树的最左节点)
BST<DataType>::BinNodePointer xSucc = x->right;
parent = x;
while (xSucc->left != 0) {
parent = xSucc;
xSucc = xSucc->left;
}
x->data = xSucc->data;//将xSucc中的内容移动到x中,修改x为指向被删除的后继
x = xSucc;
}
//处理只有一个节点或者没有结点的情况
BST<DataType>::BinNodePointer subtree = x->left;//指向x的子树的指针
if (subtree == 0) {//如果指针为空说明x的左子为空 subtree指向x的右子
subtree = x->right;
}
if (parent == 0) { myRoot = subtree; }
else if (parent->left == x) { parent->left = subtree; }
else { parent->right = subtree; }
delete x;
}
template<typename DataType>
inline void BST<DataType>::inorderAux(ostream& out, BST<DataType>::BinNodePointer subtreeptr) const
{
if (subtreeptr != 0) {
inorderAux(out, subtreeptr->left);
out << subtreeptr->data << " ";
inorderAux(out, subtreeptr->right);
}
}
template<typename DataType>
inline void BST<DataType>::foreOrderAux(ostream& out, BST<DataType>::BinNodePointer subtreeptr) const
{
if (subtreeptr != 0) {
out << subtreeptr->data << " ";
foreOrderAux(out, subtreeptr->left);
foreOrderAux(out, subtreeptr->right);
}
}
template<typename DataType>
inline void BST<DataType>::afterOrderAux(ostream& out, BST<DataType>::BinNodePointer subtreeptr) const
{
if (subtreeptr != 0) {
afterOrderAux(out, subtreeptr->left);
afterOrderAux(out, subtreeptr->right);
out << subtreeptr->data << " ";
}
}
template<typename DataType>
inline void BST<DataType>::deleteAux(const DataType& item, bool& found, BST<DataType>::BinNodePointer& locptr, BST<DataType>::BinNodePointer& parent) const
{
locptr = myRoot;
parent = 0;
found = false;
while (!found && locptr != 0) {
if (item < locptr->data) {
parent = locptr;
locptr = locptr->left;
}
else if (item > locptr->data) {
parent = locptr;
locptr = locptr->right;
}
else {
found = true;
}
}
}
template<typename DataType>
inline void BST<DataType>::BSTAux(BST<DataType>::BinNodePointer& ptr)
{
if (ptr != 0) {
BSTAux(ptr->left);
BSTAux(ptr->right);
delete ptr;
}
}
template<typename DataType>
inline void BST<DataType>::graphHorizontal(ostream& out) const
{
horizontalGraphAux(out, 0, myRoot);
}
template<typename DataType>
inline void BST<DataType>::horizontalGraphAux(ostream& out, int indent, BST<DataType>::BinNodePointer subtreeRoot) const
{
if (subtreeRoot != 0) {
horizontalGraphAux(out, indent + 8, subtreeRoot->right);
out << setw(indent) << " " << subtreeRoot->data << endl;
//setw当后面紧跟着的输出字段长度小于 n 的时候,在该字段前面用空格补齐,当输出字段长度大于 n 时,全部整体输出。
horizontalGraphAux(out, indent + 8, subtreeRoot->left);
}
}
template<typename DataType>
inline void BST<DataType>::verticalGraghAux(BST<DataType>::BinNodePointer ptr, vector<DataType>& elementVector)const
{
if (ptr != 0) {
verticalGraghAux(ptr->left, elementVector);
elementVector.push_back(ptr->data);
verticalGraghAux(ptr->right, elementVector);
}
}
template<typename DataType>
inline void BST<DataType>::SortAux(BST<DataType>::BinNodePointer subtreeptr, vector<DataType>& v) const
{
if (subtreeptr != 0) {
SortAux(subtreeptr->left, v);
v.push_back(subtreeptr->data);
SortAux(subtreeptr->right, v);
}
}
template<typename DataType>
inline void BST<DataType>::graphVertical(ostream& out) const
{
vector<DataType> v;
verticalGraghAux(myRoot, v);
queue<BST<DataType>::BinNodePointer> q;
q.push(myRoot);
while (!q.empty()) {
vector<BST<DataType>::BinNodePointer> cache;
//把处在同一行的节点拉出来
while (!q.empty()) { cache.push_back(q.front()); q.pop(); }
map<DataType, int> elementMap;
for (auto p : cache) {
if (p) {
//找当前节点中序遍历位置
typename vector<DataType>::iterator iter;
iter = find(v.begin(), v.end(), p->data);
int index = iter - v.begin();
elementMap.insert(pair<DataType, int>(p->data, index));
//孩子节点入队
if (p->left) q.push(p->left);
if (p->right) q.push(p->right);
}
}
typename map<DataType, int>::iterator iter;
int gap = 0;
for (iter = elementMap.begin(); iter != elementMap.end(); iter++)
{
for (int i = 0; i < iter->second - gap; i++) {
out << " ";
}
cout << iter->first;
gap = iter->second;
}
out << endl;
}
}
template<typename DataType>
inline vector<DataType> BST<DataType>::sortToVector() const
{
vector<DataType> v1;
SortAux(myRoot, v1);
return v1;
}
#pragma once
快排
template<class T>
void QuickSort(vector<T>& x, int first, int last)
{
int pos = 0;
if (first < last) {
pos = split(x, first, last);
QuickSort(x, first, pos - 1);
QuickSort(x, pos + 1, last);
}
}
template<class T>
int split(vector<T>& x, int first, int last)
{
T pivot = x[first];
int left = first,//序列开始头部
right = last;//序列开始尾部
while (left < right) {//结束条件为标记头和标记尾碰到一起
while (pivot < x[right]) {
//从从右往左开始,为何?
//因为如果从左往右 该序列有序且服从从小到大,则left会一直++,直至越界报错
right--;
}
while (left < right && (x[left] <= pivot)) {
//如果做标记没有碰到右标记,且当前左标记所在的值小于pivot
left++;
}
if (left < right) {//交换左标记点和右标记点的值
int temp = x[left];
x[left] = x[right];
x[right] = temp;
}
}
//左标记点和有标记点碰到一起,交换pivot和左右标记点所在点的值
int pos = right;
x[first] = x[pos];
x[pos] = pivot;
return pos;//返回当前界值
}
堆排序
template<class T>
void HeapSort(vector<T>& x)
{
int count = 0;
makeHeapify(x);//进行建堆,x[i]必大于x[i*2]和x[i*2+1]
for (int i = x.size() - 1; i >= 2; i--) {
//进行根叶交换
T temp = x[i];
x[i] = x[1];
x[1] = temp;
//进行下调
percolate_down(1, i - 1, x);
}
}
//建堆算法
template<class T>
void makeHeapify(vector<T>& x) {
int n = x.size() - 1;
for (int i = n / 2; i >= 1; i--) {
percolate_down(i, n, x);//对i为根的子树进行下调算法
}
}
//下调算法(只有x[index]中的值不满足堆次序条件,把这个近似堆调整成堆)
template<class T>
void percolate_down(int index, int last, vector<T>& x) {
int c = index * 2;
int n = last;
bool flag = false;
while (c <= n && !flag) {//c是左子节点的位置
if (c < n && x[c] < x[c + 1]) {//如果index有两个子节点并且右子节点比较大
c++;
}
if (x[index] < x[c]) {//双亲节点不满足堆次排序
T temp = x[index];
x[index] = x[c];
x[c] = temp;
index = c;//可能弄乱了以c为根的二叉树,检查其下的二叉树
c = 2 * c;
}
else {
flag = true;//条件满足,结束循环
}
}
}
//上调算法,在其中添加一个元素,并使得排序仍然满足是一个堆
template<class T>
void percolate_up(vector<T>& x, T item) {
x.push_back(item);
bool flag = false;
int itemLocation = x.size() - 1;
int parentLocation = itemLocation / 2;
while (parentLocation >= 1 && !flag) {
if (x[parentLocation] < x[itemLocation]) {
T temp = x[parentLocation];
x[parentLocation] = x[itemLocation];
x[itemLocation] = temp;
itemLocation = parentLocation;
parentLocation /= 2;
}
else { flag = true; }
}
}
运行结果
本系列算法开篇内容整理自:https://www.runoob.com/w3cnote/ten-sorting-algorithm.html
其余内容为数据结构相关内容自行编程
排序算法是《数据结构与算法》中最基本的算法之一。