一、交换排序之~~冒泡排序
1.一种简单的交换排序
将序列中的数据,从前向后遍历循环,作为被比较数;(外循环)
将剩余数据作为比较数,从前向后,依次进行比较;(内循环)
把较小数据的交换到靠前位置;
每一次循环比较,都能将剩余数据中最小的数据交换到最前边,
思想简单,效率最低。
2.冒泡排序
将序列中的数据,从前向后遍历,控制循环;(外循环)
将序列中的数据,从后向前遍历,将相邻两个数据进行比较,小数交换到靠前位置;(内循环)
这样的排序,每次循环比较,不仅能将最小的数据交换到最前边,还能将其他较小数据的位置向前挪;
效率有所提升。
3.冒泡排序的优化版本
设置状态变量Flag
将序列中的数据,从前向后遍历,控制循环;每次循环开始,将Flag置为False;
将序列中的数据,从后向前遍历,相邻两个数据进行比较,小数交换到靠前位置,且发生交换,则Flag置为True;
当某次外循环,数据已经有序,则遍历过程中不发生数据交换,Flag一直处于False状态,直接跳出外循环,认为排序结束。
这样的排序,若序列已经有序,则无需继续进行排序;
效率进一步提升。
二、交换排序之~~快速排序
从序列中选择关键字(如第一个数据)
一趟排序:按照关键词,将输入序列分为两部分,左部分比关键字小,右部分比关键字大;
分别对得到的这两部分再次进行排序,递归完成排序;
四种交换排序代码如下:
//三种冒泡排序算法比较
// 快速排序
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
void BubbleSortLow(vector <int> chaosData, int num);
void BubbleSortMid(vector <int> chaosData, int num);
void BubbleSortHight(vector <int> chaosData, int num);
int QuickSortPar(vector <int> &chaosData, int low, int high);
void QuickSort(vector <int> &chaosData, int low, int high);
int SwapNum(int &num1, int &num2);
int main()
{
int num = 10;
srand((unsigned)time(NULL));
cout << "功能:将数据从大到小排序\n" << endl;
vector <int> chaosData;
for (int i = 0; i != num; ++i)
{
chaosData.push_back(rand() % 100); //产生0~100的整型数据
}
cout << "排序前数据为:" << endl;
for (auto c : chaosData)
{
cout << c << " ";
}
cout << endl << "1.效率较低的一种冒泡排序:" << endl;
clock_t clockLowB = clock();
BubbleSortLow(chaosData, num);
clock_t clockLowE = clock();
cout << "第1种方法运行时间为:" << (double)(clockLowE - clockLowB) << "毫秒" << endl;
cout << endl << "2.正宗的一种冒泡排序:" << endl;
clock_t clockMidB = clock();
BubbleSortMid(chaosData, num);
clock_t clockMidE = clock();
cout << "第2种方法运行时间为:" << (double)(clockMidE - clockMidB) << "毫秒" << endl;
cout << endl << "3.优化后的一种冒泡排序:" << endl;
clock_t clockHighB = clock();
BubbleSortHight(chaosData, num);
clock_t clockHighE = clock();
cout << "第3种方法运行时间为:" << (double)(clockHighE - clockHighB) << "毫秒" << endl;
vector <int> &chaosDataNew = chaosData;
cout << endl << "4.快速排序:" << endl;
clock_t clockQuickB = clock();
QuickSort(chaosDataNew, 0, num - 1);
clock_t clockQuickE = clock();
cout << "第4种方法运行时间为:" << (double)(clockQuickE - clockQuickB) << "毫秒" << endl;
cout << "排序后数据为:" << endl;
for (auto c : chaosDataNew)
{
cout << c << " ";
}
system("pause");
return 0;
}
// 0.交换两个整型数据
int SwapNum(int &num1, int &num2)
{
int tempNum = 0;
tempNum = num1;
num1 = num2;
num2 = tempNum;
return 0;
}
// 1.效率较低的一种冒泡排序
void BubbleSortLow(vector <int> chaosData, int num)
{
for (int i = 0; i != num-1; ++i)
{
for (int j = i + 1; j != num; ++j)
{
if (chaosData[i] > chaosData[j])
{
SwapNum(chaosData[i], chaosData[j]);
}
}
}
cout << "排序后数据为:" << endl;
for (auto c : chaosData)
{
cout << c << " ";
}
}
// 2.正宗的一种冒泡排序:
void BubbleSortMid(vector <int> chaosData, int num)
{
for (int i = 0; i <= num - 1; ++i)
{
for (int j = num - 1; j >= i && j > 0; --j) // j>i
{
if (chaosData[j-1] > chaosData[j])
{
SwapNum(chaosData[j-1], chaosData[j]);
}
}
}
cout << "排序后数据为:" << endl;
for (auto c : chaosData)
{
cout << c << " ";
}
}
// 3.优化后的一种冒泡排序:
void BubbleSortHight(vector <int> chaosData, int num)
{
int flag; // 为1则已经有序
for (int i = 0; i <= num - 1; ++i) // 循环判断:i未至最大数值 且 此时无序;flag为1则跳出循环
{
flag = 1; //无序
for (int j = num - 1; j >= i && j > 0; --j)
{
if (chaosData[j - 1] > chaosData[j])
{
SwapNum(chaosData[j - 1], chaosData[j]);
flag = 0;
}
}
if (flag == 1)
break;
}
cout << "排序后数据为:" << endl;
for (auto c : chaosData)
{
cout << c << " ";
}
}
// 4.快速排序
void QuickSort(vector <int> &chaosData, int low, int high)
{
int flag;
if (low < high)
{
flag = QuickSortPar(chaosData, low, high);
QuickSort(chaosData, low, flag - 1);
QuickSort(chaosData, flag + 1, high);
}
}
int QuickSortPar(vector <int> &chaosData, int low, int high)
{
int keyNum = chaosData[low]; // 将序列中的第一个数字作为关键字
//low为左侧标志,high为右侧标志;从左到右从小到大
while (low < high)
{
while (low < high && chaosData[high] > keyNum)
{
--high;
}
SwapNum(chaosData[high], chaosData[low]);
while (low < high && chaosData[low] < chaosData[high])
{
++low;
}
SwapNum(chaosData[high], chaosData[low]);
}
cout << "调用low=" << low << " high=" << high << endl;
return low; //low和high相等
}
三、选择排序之~~简单选择排序
将序列从前向后,依次循环遍历,首先认为第一个位置的数字是最小的,记最小数字的位置为min;(外循环)
将剩余数字和第一个位置数字比较,若发现更小的数字,则将min的值改为该位置;(内循环)
每次外循环,得到min位置,将min位置和外循环开始位置的数字互换,则最小的数字被选择到了序列首位;
依次进行外循环;
四、选择排序之~~堆排序
堆的定义:
每个结点的值 大于或等于 其左右孩子结点的值(大顶堆)
每个结点的值 小于或等于 其左右孩子结点的值(小顶堆)
结点 i 的左孩子结点为:2 * i + 1;右孩子结点为: 2 * i + 2;
第一个非叶结点:len / 2 - 1;
堆排序的思想:将无序数据构造为堆结构,将堆顶元素输出,再将剩余元素重新构造为堆,继续输出堆顶元素;
问题①:如何将无序数据构造为堆结构?.
从无序数据的第一个非叶结点开始,依次调整,直到调整至根节点;
针对某个结点的堆调整,设置标号minId,,初始化为该结点的位置;
将该结点及其左右孩子结点中 最小结点的位置 赋给 minId
若minId仍然是该结点的位置,则继续调整下一个非叶结点。
否则,将该结点和最小数据结点互换位置,发并以新的minId位置作为非叶结点,重新进行堆调整;
问题②:如何将堆顶元素之外的元素重新调整为堆?
将调整好的堆结构根节点元素 与 最后位置的元素互换位置,并输出,此时得到了序列中的最小数据;
此时,最后位置的元素成为了新的根节点,通过新的根节点调整堆结构,得到新的堆,再次输出根节点,依次循环;
//选择排序
#include <iostream>
#include <ctime>
#include <Windows.h>
using namespace std;
void SelectionSort(int chaosData[], int len);
void HeapSort(int chaosData[], int len);
void adjust(int chaosData[], int len, int index);
int SwapNum(int &num1, int &num2);
int main()
{
int chaosData[10];
int len = 10;
srand((unsigned)time(NULL));
cout << "功能:对数据从大到小排序\n" << endl;
for (int i = 0; i != len; ++i)
{
chaosData[i] = (rand() % 100); //产生0~100的整型数据
}
cout << "排序前数据为:" << endl;
for (int i = 0; i < len; ++i)
{
cout << chaosData[i] << " ";
}
// cout << endl << "\n1.选择排序:" << endl;
// clock_t clockLowB = clock();
// SelectionSort(chaosData, len);
// clock_t clockLowE = clock();
// cout << "\n第1种方法运行时间为:" << (double)(clockLowE - clockLowB) << "毫秒" << endl;
cout << endl << "\n2.堆排序:" << endl;
clock_t clockMidB = clock();
HeapSort(chaosData, len);
clock_t clockMidE = clock();
cout << "\n第1种方法运行时间为:" << (double)(clockMidE - clockMidB) << "毫秒" << endl;
system("pause");
return 0;
}
// 0.交换两个整型数据
int SwapNum(int &num1, int &num2)
{
int tempNum = 0;
tempNum = num1;
num1 = num2;
num2 = tempNum;
return 0;
}
// 1.选择排序
void SelectionSort(int chaosData[], int len)
{
int i, j;
int min;
for (i = 0; i <= len - 1; ++i)
{
min = i;
for (j = i + 1;j < len; ++j)
{
if (chaosData[min] > chaosData[j])
{
min = j;
}
}
if (min != i)
{
SwapNum(chaosData[min], chaosData[i]);
}
}
cout << "排序后数据为:" << endl;
for (int i = 0; i < len; ++i)
{
cout << chaosData[i] << " ";
}
}
// 2.1堆排序算法
void HeapSort(int chaosData[], int len)
{
for (int i = len / 2 - 1; i >= 0; i--)
{
adjust(chaosData, len, i);
cout << endl;
cout << "第" << i << "个结点" << endl;
for (int i = 0; i < len; ++i)
{
cout << chaosData[i] << " ";
}
cout << endl;
}
for (int i = len - 1; i >= 1; i--)
{
SwapNum(chaosData[0], chaosData[i]);
adjust(chaosData, i, 0);
cout << "第" << i << "个结点" << endl;
for (int i = 0; i < len; ++i)
{
cout << chaosData[i] << " ";
}
cout << endl;
}
cout << "排序后数据为:" << endl;
for (int i = 0; i < len; ++i)
{
cout << chaosData[i] << " ";
}
}
// 2.2 堆排序算法,其中的调整函数,小堆顶
void adjust(int chaosData[], int len, int index)
{
int left = 2 * index + 1;
int right = 2 * index + 2;
int minId = index;
if (left < len && chaosData[minId] < chaosData[left])
{
minId = left;
}
if (right < len && chaosData[minId] < chaosData[right])
{
minId = right;
}
if (minId != index)
{
SwapNum(chaosData[minId], chaosData[index]);
adjust(chaosData, len, minId);
}
}
五、插入排序之~~直接插入排序
从前到后,循环遍历,依次将数据纳入排序队列,第一次对前2个数据排序,第二次完成前3个数据排序,第N-1次完成前N个数据排序(外循环)
每次外循环选出数据,这些数据已经排好序,并将下一个数据插入到有序表中合适位置;将待插入数据依次向前遍历,直至找到比它更小的数据,完成插入。
六、插入排序之~~希尔排序
先将序列分组排序,得到的序列基本有序,即小的关键字基本在前,大的关键字基本在后。对基本有序的序列进行直接插入排序,可以增加排序效率。
比如10个元素:【1 2 3 4 5 6 7 8 9 10】
第一次分组情况:【1 6】【2 7】【3 8】【4 9】【5 10】 增量为 5
第二次分组情况:【1 3 5 7 9】【2 4 6 8 10】 增量为2
第三次分组情况:【1 2 3 4 5 6 7 8 9 10】 增量为1
//插入排序
//直接插入排序 和 希尔排序
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
void InsertSort(vector <int> chaosData, int len); //1.直接插入排序
void ShellSort(vector <int> chaosData, int len); //2.希尔排序
int main()
{
int len = 10;
srand((unsigned)time(NULL));
cout << "功能:对数据从大到小排序\n" << endl;
vector <int> chaosData;
for (int i = 0; i != len; ++i)
{
chaosData.push_back(rand() % 100); //产生0~100的整型数据
}
cout << "排序前数据为:" << endl;
for (auto c : chaosData)
{
cout << c << " ";
}
cout << endl << "1.直接插入排序:" << endl;
clock_t clockInsertB = clock();
InsertSort(chaosData, len);
clock_t clockInsertE = clock();
cout << "\n第1种方法运行时间为:" << (double)(clockInsertE - clockInsertB) << "毫秒" << endl;
cout << endl << "2.希尔排序:" << endl;
cout << "排序前数据为:" << endl;
for (auto c : chaosData)
{
cout << c << " ";
}
clock_t clockShellB = clock();
ShellSort(chaosData, len);
clock_t clockShellE = clock();
cout << "\n第2种方法运行时间为:" << (double)(clockShellE - clockShellB) << "毫秒" << endl;
system("pause");
return 0;
}
// 1.直接插入排序
void InsertSort(vector <int> chaosData, int len)
{
int waitInsert; //需要插入的数据,首次从第1个数据开始,和第0个数据进行比较
int compPosi; //表示插入到哪些数据中,和哪些数据需要比较
for (waitInsert = 1; waitInsert != len; ++waitInsert)
{
int insData = chaosData[waitInsert]; //待插入数据,作为临时变量,最后将该数据插入到合适位置;
compPosi = waitInsert - 1;
// while要注意一点:A&&B运算符,若A为假,则无需判断B,表达式为假;
// 因此,下式中&&左右表达式不能互换,否则会出现调用chaosData[-1],越界出错;
// 用insData 和 compPosi位置的数据进行比较,若insData更小,则将compPosi位置的数据向后移动;
while ((compPosi >= 0) && (insData < chaosData[compPosi]) )
{
chaosData[compPosi + 1] = chaosData[compPosi]; //数据后移
compPosi--;
}
chaosData[compPosi+1] = insData; // 直到insData不比compPosi处的数据小,将insData赋值为compPosi+1处的数据
cout << "\n第" << waitInsert << "次排序后:" << endl;
for (auto c : chaosData)
{
cout << c << " ";
}
}
}
// 2.希尔排序
void ShellSort(vector <int> chaosData, int len)
{
int groupNum = 0; // 分组后,组内元素的位置增量,也为组数,初始化为0;
int begNum = 0;
int loopNum = 0;
for (groupNum = int(len / 2);groupNum >= 1;groupNum = int(groupNum / 2))
{
loopNum = 1;
// 最外层的循环实现了不同的分组情况
// 第二层的循环,需要分别对每个分组分别进行插入排序
for (begNum = groupNum; begNum != len; begNum++)
{
int insrtNum = chaosData[begNum]; //待插入的数据
int compPosi = begNum - groupNum; //用于比较的数据
while ((compPosi >= 0) && insrtNum < chaosData[compPosi])
{
chaosData[compPosi + groupNum] = chaosData[compPosi];
compPosi = compPosi - groupNum;
}
chaosData[compPosi + groupNum] = insrtNum;
}
cout << "\n第" << loopNum << "次分组排序后:" << endl;
loopNum++;
for (auto c : chaosData)
{
cout << c << " ";
}
}
}
七、归并排序