之前数据结构课程学的几个重要的排序算法,现在整理了一下用于回顾知识和分享
一.各排序基本思想
- 插入排序:基本思想为每一步将一个待排序的数据插入到前面已经排好序的有序序列中,直到插完所有元素为止。
- 折半插入排序:基本思想为将数组分为有序部分和待排序部分,每次按顺序从待排序列中选择一个元素,通过折半查找的方式,从有序数列部分找到待排元素的正确位置并插入
- shell排序:基本思想是把记录按下标的一定量分组,对每组使用直接插入排序的算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件被分成一组,算法结束
- 直接选择排序:基本思想是第一趟从n个元素的数据序列中选出关键字最小(或最大)的元素并放到最前(或最后)位置,下一趟再从n-1个元素中选出最小(或最大)的元素并放到次前(后)位置,以此类推,经过n-1趟完成排序
- 树形排序:基本思想是先把待排序的n个记录的关键字两两进行比较,取出较小者。然后再在 n/2 个较小者中,采用同样的方法进行比较选出每两个中的较小者,如此反复,直至选出最小关键字记录为止
- 冒泡排序:基本思想是将第一个元素和第二个元素进行比较,若为逆序则将两个元素交换,然后比较第二个元素和第三个元素。依次类推,直至第 n-1个元素和第 n个元素进行比较为止
- 快速排序:基本思想是使用分治的思想,通过一趟排序将待排序列分割成两部分,其中一部分记录的关键字均比另一部分记录的关键字小。之后分别对这两部分记录继续进行排序,以达到整个序列有序的目的
- 归并排序:归并,就是把元素合并在一起,在这里我们主要是通过把数据元素分开,当数组元素细化后将它在合并起来。在归并算法中,主要用到了分治和合并的两种思想。分治:将数组元素细化,分成n多个单个元素序列。合并:一步一步将分治的数组元素合并起来,合并的同时进行顺序排序。
二.排序算法
#include <Windows.h>
#include <iostream>
using namespace std;
//插入排序
void insertSort(int a[], int n)
{
for (int i = 1; i < n; i++)
{
int tmp = a[i];
int p = i;
for (int j = i - 1; j >= 0; j--)
{
if (tmp >= a[j]) break;
a[p] = a[j];
p = j;
}
a[p] = tmp;
}
}
//折半插入排序
void BinaryInsertSort(int a[], int n)
{
for (int i = 1; i < n; i++)
{
int tmp = a[i];
int L = 0, R = i - 1;
while (L <= R)
{
int m = (L + R) / 2;
if (a[m] > tmp) R = m - 1;
else L = m + 1;
}
int ans = L;
for (int j = i; j > L; j--)
{
a[j] = a[j - 1];
}
a[L] = tmp;
}
}
//Shell排序
void ShellSort(int A[], int n, int s)
{
int i, j, k;
int temp;
for (k = s; k > 0; k >>= 1)
{
for (i = k; i < n; i++)
{
temp = A[i];
j = i - k;
while (j >= 0 && temp < A[j])
{
A[j + k] = A[j];
j -= k;
}
A[j + k] = temp;
}
}
}
//直接选择排序
void DirectSelectSort(int a[], int n)
{
int tmp;
for (int i = 0; i < n - 1; i++)
{
int k = i;
for (int j = i + 1; j < n; j++)
{
if (a[j] < a[k])
{
k = j;
}
}
if (i != k)
{
tmp = a[k];
a[k] = a[i];
a[i] = tmp;
}
}
}
//树形排序
#define Left(i) (2 * (i) - 2 * n)
#define Right(i) (2 * (i) - 2 * n + 1)
#define Father(i) (n + (i) / 2)
//#define Brother(i) ((i) & 1 ? (i) - 1 : (i) + 1)
#define Root (2 * n - 2)
#define min(a, b) (a) < (b) ? (a) : (b)
#define INF_VALUE 0x3FFFFFFF
void TreeSort(int a[], int n)
{
int* t = new int[2 * n];
memcpy(t, a, sizeof(int) * n);
for (int k = n; k <= Root; k++)
{
t[k] = min(t[Left(k)], t[Right(k)]);
}
a[0] = t[Root];
for (int k = 1; k <= n - 1; k++)
{
int sel = Root;
int left = Left(sel);
while (left >= 0)
{
sel = (t[sel] == t[left]) ? left : (left + 1);
left = Left(sel);
}
t[sel] = INF_VALUE;
sel = Father(sel);
while (sel <= Root)
{
t[sel] = min(t[Left(sel)], t[Right(sel)]);
sel = Father(sel);
}
a[k] = t[Root];
}
delete[] t;
}
//冒泡排序
void BubbleSort(int a[], int n)
{
for (int k = 0; k < n; k++)
{
for (int i = 0; i < n - 1; i++)
{
if (a[i] > a[i + 1])
{
int tmp = a[i];
a[i] = a[i + 1];
a[i + 1] = tmp;
}
}
}
}
//快速排序
void QuickSort(int A[], int low, int high)
{
int i, j;
if (low >= high) return;
i = low;
j = high;
int temp = A[i];
while (i < j)
{
while (i < j && temp < A[j])
j--;
if (i < j)
{
A[i++] = A[j];
}
while (i < j && temp >= A[i])
i++;
if (i < j)
{
A[j--] = A[i];
}
}
A[i] = temp;
QuickSort(A, low, --j);
QuickSort(A, ++i, high);
}
// 基数排序中的队列类
class Queue {
private:
int* a;
int maxSize;
int front, rear;
public:
Queue(int sz);
~Queue();
void flush();
bool empty();
bool full();
void clear();
int size();
bool push(int x);
void pop();
int Front();
};
Queue::Queue(int sz = 10) {
maxSize = sz;
a = new int[sz];
front = rear = 0;
}
Queue::~Queue()
{
delete[] a;
}
void Queue::flush() {
delete[] a;
}
bool Queue::empty() {
return front == rear;
}
bool Queue::full() {
return rear == maxSize;
}
void Queue::clear() {
front = rear = 0;
}
int Queue::size() {
return rear - front;
}
bool Queue::push(int x) {
if (full())
return false;
a[rear++] = x;
return true;
}
void Queue::pop() {
front++;
}
int Queue::Front() {
return a[front];
}
void RadixSort(int a[], int n)
{
int max = a[0];
for (int i = 1; i < n; i++)
{
if (a[i] > max)
max = a[i];
}
int l = 0;
while (max != 0)//求出最大长度
{
max = max / 10;
l++;
}
Queue list[10];
for (int i = 1; i <= l; i++)//第i个回合
{
int x = 1;
for (int j = 0; j < n; j++)
{
int m = a[j] / x % 10;
list[m].push(a[j]);
}
x *= 10;
int y = 0;
for (int j = 0; j < 10; j++)
{
if (list[j].empty())
continue;
else
{
while (!list[j].empty())
{
a[y] = list[j].Front();
list[j].pop();
y++;
}
}
}
}
}
//归并排序
template<class T>
void TwoWayMerge(T Dst[], T Src[], int s, int e1, int e2)
//两个子文件归并为一个子文件
//源数组中[s:e1]和[e1+1:e2]归并到目的数组中[s:e2]
{
int s1, s2;
for (s1 = s, s2 = e1 + 1; s1 <= e1 && s2 <= e2;)
{
if (Src[s1] <= Src[s2])
Dst[s++] = Src[s1++];
else
Dst[s++] = Src[s2++];
}
if (s1 <= e1)
memcpy(&Dst[s], &Src[s1], (e1 - s1 + 1) * sizeof(T));
else
memcpy(&Dst[s], &Src[s2], (e2 - s2 + 1) * sizeof(T));
}
template<class T>
void OnePassMerge(T Dst[], T Src[], int Len, int n)
//一趟归并:每两个相邻子文件归并,子文件长度为Len
{
int i;
for (i = 0; i + 2 * Len < n; i += 2 * Len)
TwoWayMerge(Dst, Src, i, i + Len - 1, i + 2 * Len - 1);
if (i < n - Len)
TwoWayMerge(Dst, Src, i, i + Len - 1, n - 1);
else
memcpy(&Dst[i], &Src[i], (n - i) * sizeof(T));
}
template<class T>
void MergeSort(T A[], int n)
{
int k = 1; // 初始子文件长度
T* B = new T[n];
while (k < n)
{
OnePassMerge(B, A, k, n);
k <<= 1;
if (k >= n)
memcpy(A, B, n * sizeof(T));
else
{
OnePassMerge(A, B, k, n);
k <<= 1;
}//交叉使用A,B,效率高
}
}
三.算法性能测试
- 1.性能测试代码
int main()
{
//生成随机数
//排序时间
//直接插入排序
int x[100000];
srand(time(0));
for (int i = 0; i < 100000; i++)
{
x[i] = rand() * rand();
}
DWORD startTime1 = GetTickCount64();//计时开始
insertSort(x, 100000);
DWORD endTime1 = GetTickCount64();//计时结束
cout << "The insertSort time is:" << endTime1 - startTime1 << "ms" << endl;
//折半插入排序
srand(time(0));
for (int i = 0; i < 100000; i++)
{
x[i] = rand() * rand();
}
DWORD startTime2 = GetTickCount64();//计时开始
BinaryInsertSort(x, 100000);
DWORD endTime2 = GetTickCount64();//计时结束
cout << "The BinaryInsertSort time is:" << endTime2 - startTime2 << "ms" << endl;
//Shell排序
srand(time(0));
for (int i = 0; i < 100000; i++)
{
x[i] = rand() * rand();
}
DWORD startTime3 = GetTickCount64();//计时开始
ShellSort(x, 100000,50000);
DWORD endTime3 = GetTickCount64();//计时结束
cout << "The ShellSort time is:" << endTime3 - startTime3 << "ms" << endl;
//直接选择排序
srand(time(0));
for (int i = 0; i < 100000; i++)
{
x[i] = rand() * rand();
}
DWORD startTime4 = GetTickCount64();//计时开始
DirectSelectSort(x, 100000);
DWORD endTime4 = GetTickCount64();//计时结束
cout << "The DirectSelectSort time is:" << endTime4 - startTime4 << "ms" << endl;
//树形排序
srand(time(0));
for (int i = 0; i < 100000; i++)
{
x[i] = rand() * rand();
}
DWORD startTime5 = GetTickCount64();//计时开始
TreeSort(x, 100000);
DWORD endTime5 = GetTickCount64();//计时结束
cout << "The TreeSort time is:" << endTime5 - startTime5 << "ms" << endl;
//冒泡排序
srand(time(0));
for (int i = 0; i < 100000; i++)
{
x[i] = rand() * rand();
}
DWORD startTime6 = GetTickCount64();//计时开始
BubbleSort(x, 100000);
DWORD endTime6 = GetTickCount64();//计时结束
cout << "The BubbleSort time is:" << endTime6 - startTime6 << "ms" << endl;
//快速排序
srand(time(0));
for (int i = 0; i < 100000; i++)
{
x[i] = rand() * rand();
}
DWORD startTime7 = GetTickCount64();//计时开始
QuickSort(x, 0,99999);
DWORD endTime7 = GetTickCount64();//计时结束
cout << "The QucikSort time is:" << endTime7 - startTime7 << "ms" << endl;
//归并排序
srand(time(0));
for (int i = 0; i < 100000; i++)
{
x[i] = rand() * rand();
}
DWORD startTime8 = GetTickCount64();//计时开始
MergeSort(x, 100000);
DWORD endTime8 = GetTickCount64();//计时结束
cout << "The MergeSort time is:" << endTime8 - startTime8 << "ms" << endl;
return 0;
}
- 2.测试结果