排序算法总结
前言
本人菜鸟一枚,程序均为C++编写,如有错误,欢迎平均区指出,一定积极改正,共同学习!
7种排序算法
①冒泡排序
②选择排序
③插入排序
④快速排序
⑤归并排序
⑥基数排序
⑦堆排序
低级排序:冒泡,选择,插入
高级排序:快速排序,归并排序
1. 冒泡排序
从左向右扫描数据,选择最大的数据放到右边(n个数据扫描n-1个遍)
要点:比较相邻的两个数,如果左边的数大于右边的数就进行交换
双循环:外循环(扫描次数) 内循环(比较次数)
#include <iostream>
using namespace std;
void BubbleSort(int list[], int n);
int main()
{
int a[] = { 1,4,2,9,5,7,3 };
for (int i = 0; i < 7; i++)
cout << a[i] << " ";
cout << endl;
BubbleSort(a, 7);
for (int i = 0; i < 7; i++)
cout << a[i] << " ";
cout << endl;
system("pause");
return 0;
}
void BubbleSort(int list[], int n)
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (list[j] > list[j + 1])
swap(list[j], list[j + 1]);
}
}
}
2.选择排序
选择排序算法
比冒泡排序快一点,扫描结束后,只交换一次,放在最右边
从当前未排序的整数中找一个最小的整数,将它放在已排序的整数列表的最后
要点: 选择排序选最小的,往左边选
#include <iostream>
using namespace std;
void SelectSort(int *list, const int n);
int main()
{
int a[] = { 1,3,5,7,2,4,6,8 };
SelectSort(a, 8);
for (int k = 0; k < 8; k++)
cout << a[k] << " ";
cout << endl;
system("pause");
return 0;
}
void SelectSort(int *list, const int n)
{
for(int i=0;i<n-1;i++)
{
int min=i;
for(int j=i+1;j<n;j++)
{
if(list[j]<list[min])
min=j;
}
swap(list[i],list[min]);
}
}
3. 插入排序
插入排序算法
用两个变量来循环,out用来循环房间里面的人,in用来循环房间外面的人,假设开始的时候有一个人出去了。
#include<iostream>
using namespace std;
template <class T>
void InsertionSort(T *a, int n);
int main()
{
int list[] = {1,3,5,7,2,4,6,8};
InsertionSort(list, 8);
for (int k = 0; k < 8; k++)
cout << list[k];
cout << endl;
system("pause");
return 0;
}
template<class T>
void InsertionSort(T *a, const int n)
{
int in, out; //out=0这个人已经出去了a
for (out = 1; out < n; out++)
{
in = out;
T temp = a[out];
while (in > 0 && a[in - 1] >= temp)
{
a[in] = a[in - 1];
in--;
}
a[in] = temp;
}
}
4. 快速排序
1.最流行的排序算法,速度最快的排序算法
2. pivot:枢轴/枢纽 (先是最左边或最右边的作为枢轴标准)小的放左边 大的放右边
3. 递归
#include<iostream>
using namespace std;
template<class T>
void QuickSort(T *a, const int left, const int right);
int main()
{
int list[] = { 1,3,5,7,2,4,6,8,99 };
QuickSort(list, 0, 7);
for (int i = 0; i < 8; i++)
cout << list[i] << endl;
system("pause");
return 0;
}
template<class T>
void QuickSort(T *a, const int left, const int right)
{
if (left < right)
{
//选择枢轴进行划分
int i, j;
i = left;
j = right + 1;
int pivot = a[left];
do {
do i++; while (a[i] < pivot);
do j--; while (a[j] > pivot);
if (i < j)
swap(a[i], a[j]);
} while (i < j);
swap(a[left], a[j]);
QuickSort(a,left,j-1);
QuickSort(a,j+1,right);
}
}
5. 归并排序
归并排序
迭代
把两个排序好的数组归并成一个数组
把一个没有排序的数组,选两个数(当作已经排序好的数组)进行归并,归并成一个数组
#include<iostream>
#include<algorithm>
using namespace std;
void Merge(int *list, int l, int m, int h);
void MergeSort(int *list, const int l, const int h);
void Merge(int *list, int l, int m, int h)
{
int i = l;
int j = m + 1;
int k = 0;
int *temp = new int[h - l + 1];
while (i <= m && j <= h)
{
if (list[i] <= list[j])
temp[k++] = list[i++];
else
temp[k++] = list[j++];
}
while (i <= m)
temp[k++] = list[i++];
while (j <= h)
temp[k++] = list[j++];
for (i = l, k = 0; i <= h; i++, k++)
list[i] = temp[k];
delete []temp;
//copy函数 copy(a,a+n,arr) 被拷贝参数范围[a,a+n) arr拷贝到的位置
}
//两个数组归并为一个数组
//n是一共有多少个数要合并,l和m都是数组下标
//l为要归并的数组的第一个数下标 m为要归并的数组的最后一个数下标
void MergeSort(int *List, const int l, const int h)
{
if (l < h)
{
int m = l + (h - l) / 2;
MergeSort(List, l, m);
MergeSort(List, m + 1, h);
Merge(List, l, m, h);
}
else return;
}
int main()
{
int list[] = {0,26,5,77,1,61,11,59,15,48,19};//a[0]是不用的
MergeSort(list, 1, 10);
for (int k = 1; k <=10; k++)
cout << list[k] << " ";
cout << endl;
system("pause");
return 0;
}
6. 基数排序
基数排序
1.基数 十进制的基数是10,二进制的基数是2,…
2.示例
未排数组 -> 421 240 035 532 305 430 124
按个位排 -> (240 430) (421) (532) (124) (035 305)
按十位排 -> (305) (421 124) (430 532 035) (240)
按百位排 -> (035) (124) (240) (305) (421 430) (532)
()小括号把数放在一堆 实际上是把这些数放在一个链表里面
LSD最低位优先 先排低位再排高位
用链表来做 桶、箱、堆 -> 使用链表
MSD最高位优先
#include<iostream>
#include<algorithm>
#include<list>
using namespace std;
void radixsort(int data[], int n);
int maxdigit(int data[], int n);
int main()
{
cout << "test ok!"<<endl;
int data[10] = { 179,208,306,93,859,984,55,9,271,33 };
radixsort(data, 10);
for (int i = 0; i < 10; i++)
cout << data[i] << endl;
system("pause");
return 0;
}
int maxdigit(int data[], int n)
{
int d = 1;
int p = 10;
for (int i = 0; i < n; i++)
{
while (data[i] > p)
{
p = p * 10;
++d;
}
}
return d;
}
void radixsort(int data[], int n)
{
int digits = maxdigit(data, n);
int factor,d,k;
list<int> lists[10];
for (d=1,factor=1;d <= digits;d++,factor *= 10)
{
for (int i = 0; i < n; i++)
{
lists[(data[i] / factor) % 10].push_back(data[i]);
}
for (int j = k = 0; j < n; k++)
{
while (!lists[k].empty())
{
data[j++] = lists[k].front();
lists[k].pop_front();
}
}
}
}
7. 堆排序
把未排序的数据一个一个放入堆里,然后再一个一个取出来
哈希 O(1) 二叉树O(logN) 线性查找 O(N) 冒泡排序 O(N^2)
自己创建一个大顶堆
MaxHeap.h
#pragma once
#ifndef _MAXHEAP_H
#define _MAXHEAP_H
using namespace std;
template<class T>
class MaxHeap
{
public:
MaxHeap(int mx = 10);//构造函数,默认堆的大小为10
virtual ~MaxHeap();
bool IsEmpty();
void Push(const T&);
void Pop();//把根删除
const T& Top() const;//获取根里的数据
void trikleUp(int index);//向上渗透
void trikleDown(int index);//向下
private:
T *heapArray;
int maxSize;
int currentSize;
};
template<class T>
MaxHeap<T>::MaxHeap(int mx)
{
if (mx < 1) throw"max size must be >= 1";
maxSize = mx;
currentSize = 0;
heapArray = new T[maxSize];
}
template<class T>
MaxHeap<T>::~MaxHeap()
{
delete[] heapArray;
}
template<class T>
bool MaxHeap<T>::IsEmpty()
{
return currentSize == 0;
}
template<class T>
void MaxHeap<T> ::trikleUp(int index)
{
int parent = (index - 1) / 2;
T bottom = heapArray[index];
while (index > 0 && heapArray[parent] < bottom)
{
heapArray[index] = heapArray[parent];
index = parent;
parent = (parent - 1) / 2;
}
heapArray[index] = bottom;
}
template<class T>
void MaxHeap<T>::Push(const T& e)
{
if (currentSize == maxSize)
throw"MaxHeap is full";
heapArray[currentSize] = e;
trikleUp(currentSize);
currentSize++;
}
template<class T>
void MaxHeap<T>::Pop()
{
heapArray[0] = heapArray[--currentSize];
trikleDown(0);
}
template<class T>
const T& MaxHeap<T>::Top() const
{
return heapArray[0];
}
template<class T>
void MaxHeap<T> ::trikleDown(int index)
{
T top = heapArray[index];//把临时的根保存起来
int largerChild;//每个节点的两个儿子大的一个
while (index < currentSize/2 )
{
int leftChild = 2 * index + 1;
int rightChild = leftChild + 1;
//有一种情况,只有左儿子,没有右儿子 判断右儿子
if (rightChild < currentSize && heapArray[leftChild] < heapArray[rightChild])
largerChild = rightChild;
else
largerChild = leftChild;
if (top >= heapArray[largerChild])
break;
heapArray[index] = heapArray[largerChild];
index = largerChild;
}
heapArray[index] = top;
}
#endif // !_MAXHEAP_H
把未排序的数据一个一个放入堆里,然后再一个一个取出来
#include<iostream>
#include<algorithm>
#include"MaxHeap.h"
using namespace std;
int main()
{
cout << "test ok!" << endl;
MaxHeap<int> h(100);
int arr[] = { 62,3,90,27,33,8,12,9,43,66 };
for (int i = 0; i < 10; i++)
h.Push(arr[i]);
for (int i = 0; i < 10; i++)
{
arr[i] = h.Top();
h.Pop();
}
for (int i = 0; i < 10; i++)
cout << arr[i] << endl;
system("pause");
return 0;
}