好用常用的排序算法
标签(空格分隔): 算法学习
常见的八大排序算法:插入排序,选择排序,堆排序,快速排序,冒泡排序,归并排序,希尔排序,基数排序。其中笔者常用的排序算法:对于数据量较小通常采用插入排序,数据量较大选择快速排序,数据量较大且要求稳定性通常选择归并排序。
1、插入排序
1.1 算法原理:插入排序就是每一步都将一个待排数据按其大小插入到已经排序的数据中的适当位置,直到全部插入完毕。(类比打扑克牌接牌是的插入顺序一样)
1.2 C++代码
#include<iostream>
#include<stdlib.h>
void insertSort(int *pointer, int length);
int main()
{
int a[100];
//产生1-100的随机数
for (int i = 0; i < 100; i++)
{
a[i] = rand()%100;
}
printf("the original numbers are:\n");
for (int i = 0, count = 0; i < 100; i++)
{
printf("%5d", a[i]);
count++;
if (count % 6 == 0)
printf("\n");
}
//进行插入排序
insertSort(a, 100);
printf("\nthe sorted numbers are :\n");
for (int i = 0,count = 0; i < 100; i++)
{
printf("%5d",a[i]);
count++;
if (count % 6 == 0)
printf("\n");
}
getchar();
getchar();
return 0;
}
void insertSort(int *a, int length)
{
int key,i;
for (int j = 1; j < length; j++)
{
key = a[j];
i = j;
while (i>0 && a[i-1]<key)
{
a[i] = a[i-1];
i = i - 1;
}
a[i] = key;
}
}
2、快速排序
2.1 算法原理:快速排序是找出一个元素(理论上可以随便找一个)作为基准(pivot),然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值 都不小于基准值,如此作为基准的元素调整到排序后的正确位置。递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正 确位置,排序完成。所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归。
2.2 C++代码
#include <iostream>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>
#include<fstream>
#define N (1024*1024)
using namespace std;
void PrintArr(int *pnArr, int nLen)
{
for (int i = 0; i < nLen; i++)
{
printf("%d ", pnArr[i]);
}
printf("\n");
}
void Swap(int *p1, int *p2)
{
int nTmp = *p1;
*p1 = *p2;
*p2 = nTmp;
}
//实现对子数组[nLeft - nRight]的原址重排,将主元素放到合适位置
//递增排序
int Patition1(int *pnArr, int nLeft, int nRight)
{
int nKey = pnArr[nRight];
int i = nLeft - 1;
for (int j = nLeft; j < nRight; j++)
{
if (pnArr[j] <= nKey)
{
i++;
Swap(&pnArr[i], &pnArr[j]);
}
}
//将主元素插入到中间位置
Swap(&pnArr[i + 1], &pnArr[nRight]);
return i + 1;
}
//递增排序
int Patition2(int *pnArr, int nLeft, int nRight)
{
int nKey = nRight;
int i = nLeft - 1;
bool bExchange = false;
for (int j = nLeft; j < nRight; j++)
{
if (pnArr[j] < pnArr[nKey])
{
i++;
Swap(&pnArr[i], &pnArr[j]);
bExchange = true;
}
}
Swap(&pnArr[i + 1], &pnArr[nRight]);
if (bExchange)
{
return i + 1;
}
else
{
return (nLeft + nRight) / 2;
}
}
//递减排序
int Patition3(int *pnArr, int nLeft, int nRight)
{
int nKey = nRight;
int i = nLeft - 1;
for (int j = nLeft; j < nRight; j++)
{
if (pnArr[j] > pnArr[nKey])
{
i++;
Swap(&pnArr[i], &pnArr[j]);
}
}
Swap(&pnArr[i + 1], &pnArr[nRight]);
return i + 1;
}
//寻找一个nTmpPos下标,nTmpPos左边的值都小于它,右边的值都大于它
void QuickSort(int *pnArr, int nLeft, int nRight)
{
if (nLeft < nRight)
{
//分解
int nTmpPos = Patition1(pnArr, nLeft, nRight);
//解决/合并
QuickSort(pnArr, nLeft, nTmpPos - 1);
QuickSort(pnArr, nTmpPos + 1, nRight);
}
}
int main()
{
srand(time(NULL));
clock_t start, end;
//int nArr[N];
int *nArr = (int *)malloc(sizeof(int)*N);
memset(nArr, 0, sizeof(int)*N);
for (int i = 0; i < N; i++)
{
nArr[i] = rand() % N;
}
//PrintArr(nArr, 10);
start = clock();
QuickSort(nArr, 0, N - 1);
end = clock();
cout<< "time = " << double(end - start) / CLK_TCK << "sec!" << endl;
//////////////////////////////////////////////////////////////////////////将排序结果写入到文件中/////////////////////////
ofstream outFile;
outFile.open("sorted.txt");
for (int i = 0; i < N - 1; i++)
{
outFile << nArr[i] << endl;
}
free(nArr);
//PrintArr(nArr, 10);
system("pause");
return 0;
}
3、归并排序
3.1 算法原理: 归并排序,它采取分而治之的策略,将两个已经排序的序列合并成一个序列的操作。
时间复杂度是Θ(nlgn),优于插入排序算法。
算法描述
1) 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2) 设定两个指针,最初位置分别为两个已经排序序列的起始位置
3) 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4) 重复步骤3直到某一指针达到序列尾
5) 将另一序列剩下的所有元素直接复制到合并序列尾
特点:归并排序是稳定的排序.即相等的元素的顺序不会改变, 速度仅次于快速排序,但较稳定。
3.2 C++代码
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>
#include <iostream>
#include<fstream>
#define SCALE 200000
void PrintArr(int *pnArr, int nLen)
{
for (int i = 0; i < nLen; i++)
{
printf("%d ", pnArr[i]);
}
printf("\n");
}
//合并两个数组
void Merge(int data[], int nLpos, int nRpos, int nRightEnd)
{
int i;
int k = nLpos;
int nLeftEnd = nRpos;
int nTmpPos = 0;
int nLen = nRightEnd - nLpos + 1;
int *pnArr = (int *)malloc(sizeof(int) * nLen);
++nRpos;
while (nLpos <= nLeftEnd && nRpos <= nRightEnd)
{
if (data[nLpos] <= data[nRpos])
{
pnArr[nTmpPos++] = data[nLpos++];
}
else
{
pnArr[nTmpPos++] = data[nRpos++];
}
}
//当左边数组或者右边数组其中之一数据完全在数组中排好序时
while (nLpos <= nLeftEnd)
{
pnArr[nTmpPos++] = data[nLpos++];
}
while (nRpos <= nRightEnd)
{
pnArr[nTmpPos++] = data[nRpos++];
}
nTmpPos = 0;
for (i = k; i <= nRightEnd; i++)
{
data[i] = pnArr[nTmpPos++];
}
free(pnArr);
}
//排序
void MergeSort(int *pnArr, int nLeft, int nRight)
{
if (nLeft > nRight)
{
return;
}
if (nRight > nLeft)
{
//1分解,可分解成若干份
int nMid = (nLeft + nRight) / 2;
//2解决
MergeSort(pnArr, nLeft, nMid);
MergeSort(pnArr, nMid + 1, nRight);
//3合并
Merge(pnArr, nLeft, nMid, nRight);
}
}
int main()
{
srand(time(NULL));
//int nArr[SCALE];
int* nArr = (int *)malloc(sizeof(int)*SCALE);
memset(nArr, 0, sizeof(int)*SCALE);
for (int i = 0; i < SCALE; i++)
{
nArr[i] = rand() % SCALE;
}
clock_t start, end;
start = clock();
/*printf("排序前:");
PrintArr(nArr, SCALE);*/
std::ofstream outFile;
/*outFile.open("random.txt");
for (int i = 0; i < SCALE; i++)
outFile << "nArr["<<i<<"]"<<nArr[i] << std::endl;
outFile.close();*/
MergeSort(nArr, 0, SCALE-1);
end = clock();
std::cout << "time = " << double(end - start) / CLK_TCK << "sec" << std::endl;
/*printf("排序后:");
PrintArr(nArr, SCALE);*/
outFile.open("sorted1.txt");
for (int i = 0; i < SCALE; i++)
outFile << "nArr[" << i << "]=" << nArr[i] << std::endl;
outFile.close();
free(nArr);
return 0;
}