插入排序
直接插入排序
- 直接插入排序是最简单的排序方法,每次将一个待排序的记录,插入已经排好序的数据序列中,得到一个新的长度增1的有序表。
#include <iostream>
using namespace std;
#define Maxsize 100
//直接插入排序
void StraightInsertSort(int r[], int n)
{
int i, j;
for (i = 2; i <= n; i++) //r[i]插入有序子表
{
if (r[i] < r[i - 1]) //r[i]和前一个元素r[i-1]比较
{
r[0] = r[i]; //r[i]暂存到r[0]中,r[0]有监视哨的作用
r[i] = r[i - 1]; //r[i-1]后移一位
for (j = i - 2; r[j] > r[0];j--) //从后向前寻找插入位置,逐个后移,直到找到插入位置
{
r[j + 1] = r[j]; //r[j]后移一位
}
r[j + 1] = r[0]; //将r[0]插入到r[j+1]位置
}
}
}
int main()
{
int i, n, r[Maxsize + 1];
cout << "请输入数列中元素个数n: " << endl;
cin >> n;
cout << "请依次输入数列中的元素:" << endl;
for (i = 1; i <= n; i++)
cin >> r[i];
StraightInsertSort(r, n);
cout << "直接插入排序结果:" << endl;
for (i = 1; i <= n; i++)
cout << r[i] << " ";
return 0;
}
交换排序
冒泡排序
- 冒泡排序是一种最简单的交换排序算法,通过两两比较关键字,如果逆序就交换,使关键字大的记录像泡泡一样冒出来放在尾部,重复执行若干次冒泡排序,最终得到有序序列。
#include <iostream>
using namespace std;
#define Maxsize 100
//冒泡排序
void BubbleSort(int r[], int n)
{
int i, j, temp;
bool flag;
i = n - 1;
flag = true;
while (i > 0 && flag) // i 层循环(比较趟数)
{
flag = false; // flag 标志位:当某一趟排序无交换时,停止循环,减少运算量
for (j = 0; j < i; j++) // j 层循环 (每趟对比次数)
{
if (r[j] > r[j + 1])
{
flag = true;
temp = r[j];
r[j] = r[j + 1];
r[j + 1] = temp;
}
}
for (j = 0; j <= i; j++)//测试每趟排序结果
cout << r[j] << " ";
cout << endl;
i--;
}
}
int main()
{
int i, n, r[Maxsize];
cout << "请输入数列中元素个数n: " << endl;
cin >> n;
cout << "请依次输入数列中的元素:" << endl;
for (i = 0; i < n; i++)
cin >> r[i];
BubbleSort(r, n);
cout << "冒泡排序结果:" << endl;
for (i = 0; i < n; i++)
cout << r[i] << " ";
return 0;
}
快速排序
快速排序算法是基于分治策略的,其思想为:
- 分解:先从数列中取出一个元素作为基准元素。以基准元素为标准,将序列分解为两个子序列,使小于或等于基准元素的子序列在左侧,使大于基准元素的子序列在右侧。
- 治理:对两个子序列进行快速排序
- 合并:将排好序的两个子序列合并在一起,得到原问题的解
#include <iostream>
using namespace std;
// 划分函数
/*
对原序列进行分解,将其分解为两个子序列,以基准元素pivot为界
左侧子序列小于等于pivot,右侧子序列大于pivot。
*/
int Partition(int r[], int low, int high)
{
int i = low, j = high, pivot = r[low]; // 基准元素
while (i < j)
{
while (i<j && r[j]>pivot) // 从右向左扫描
j--;
if (i < j)
swap(r[i++], r[j]); //r[i]和r[j]交换后, i+1 右移一位
while (i < j&& r[i]<=pivot) // 从左向右扫描
i++;
if (i < j)
swap(r[i], r[j--]); // r[i]和r[j]交换 后j-1左移一位
}
return i; //返回最终划分完成后基准元素所在的位置
}
// 划分函数改进
/*
从右向左扫描,找小于等于pivot的数R[i]
从左向右扫描,找大于pivot的数R[j]
让R[i]和R[j]交换
一直交替进行,直到i = j,这时将基准元素与R[i]交换
*/
int Partition2(int r[], int low, int high)
{
int i = low, j = high, pivot = r[low];
while (i < j)
{
while (i<j && r[j]>pivot) j--; // 向左扫描
while (i<j && r[i]<=pivot) i++; // 向右扫描
if (i < j)
swap(r[i++], r[j--]); // r[i]和r[j]交换,然后i++,j--
}
if (r[i] > pivot)
{
swap(r[i - 1], r[low]);// r[i-1]和r[low]交换
return i - 1;
}
swap(r[i], r[low]);
return i;
}
// 快速排序
/*
首先对原序列执行划分,得到划分的中间位置mid,
然后以中间位置为界,分别对左半部分(low,mid-1)执行快排
右半部分(mid+1,high)执行快排
*/
void QuickSort(int R[], int low, int high)
{
int mid;
if (low < high)
{
mid = Partition2(R, low, high); // 返回基准元素位置
QuickSort(R, low, mid - 1); // 左区间递归快速排序
QuickSort(R, mid + 1, high); // 右区间递归快速排序
}
}
int main()
{
int a[100];
int i, n;
cout << "请先输入要排序的数据的个数:" << endl;
cin >> n;
cout << "请输入要排序的数据:" << endl;
for (i = 0; i < n; i++)
cin >> a[i];
cout << endl;
QuickSort(a, 0, n - 1);
cout << "排序后的序列为:" << endl;
for (i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}
选择排序
简单选择排序
- 最简单的选择排序算法,每次从待排序序列中选择一个最小的放在前面
#include <iostream>
using namespace std;
#define Maxsize 100
// 简单选择排序
void SimpleSelectSort(int r[], int n)
{
int i, j, k, temp;
for (i = 0; i < n-1; i++) // n-1趟
{
k = i;
for (j = i + 1; j < n; j++) //找最小值
{ //若r[k],即r[i]正好是最小的,
if (r[j] < r[k]) // 则不交换,i++,执行下一次循环
k = j;
}
if (k != i)
{
temp = r[i];
r[i] = r[k];
r[k] = temp;
}
for (j = 0; j < n; j++)//测试每趟排序结果
cout << r[j] << " ";
cout << endl;
}
}
int main()
{
int i, n, r[Maxsize];
cout << "请输入数列中的元素个数n为:" << endl;
cin >> n;
cout << "请依次输入数列中的元素:" << endl;
for (i = 0; i < n; i++)
cin >> r[i];
SimpleSelectSort(r, n);
cout << "简单选择排序结果:" << endl;
for (i = 0; i < n; i++)
cout << r[i] << " ";
return 0;
}
堆排序
- 堆可以看做一棵完全二叉树的顺序存储结构。
- 在这棵完全二叉树中,如果每一个结点的值都大于等于左右孩子结点的值,称为最大堆(大顶堆),
- 如果每一个结点的值都小于等于左右孩子结点的值,称为最小堆(小顶堆)。
堆排序充分利用堆顶记录最大(最小)的性质进行排序,每次将堆顶记录交换到最后,剩余记录调整为堆即可。
大顶堆:从小到大排列
小顶堆:从大到小排列
#include <iostream>
using namespace std;
#define maxN 100
int r[maxN];
// 下沉操作
void Sink(int k, int n)
{
while (2 * k <= n) // 如果有左孩子,k的左孩子为2k,右孩子为2k+1
{
int j = 2 * k; // j 指向左孩子
if (j < n && r[j] < r[j + 1]) // 如果有右孩子,且左孩子比右孩子小
j++; // j 指向右孩子
if (r[k] >= r[j]) // 比 “较大的孩子” 大,
break; // 已满足堆
else
swap(r[k], r[j]); // 与较大的孩子交换
k = j; //k指向交换后的新位置,继续向下比较,一直下沉到叶子
}
}
// 构建初始堆
/*
首先按照完全二叉树的顺序构建一棵完全二叉树,
然后从最后一个分支节点 n/2 开始调整,
依次将序号为 n/2 - 1,n/2-2, ..., 1的结点
执行下沉操作调整为堆
*/
void CreatHeap(int n)
{
for (int i = n / 2; i > 0; i--) //从最后一个分支结点n/2开始调整为堆,直到第一个结点
Sink(i, n);
}
// 堆排序
void HeapSort(int n)
{
CreatHeap(n); // 构建初始堆
while (n > 1)
{
swap(r[1], r[n--]); // 堆顶和最后一个记录交换,然后n-1
Sink(1, n); // 堆顶下沉
}
}
void print(int n)//输出
{
for (int i = 1; i <= n; i++)
cout << r[i] << "\t";
cout << endl;
}
int main()
{
int n;
cout << "请输入待排序记录个数:" << endl;
cin >> n;
cout << "请输入 n 个整数:" << endl;
for (int i = 1; i <= n; i++)
cin >> r[i];
cout << endl;
HeapSort(n);//堆排序
print(n);
return 0;
}
合并排序
- 合并排序采用分治策略,将一个大问题分成若干个小问题,先解决小问题,再通过小问题解决大问题。
- 可以把待排序序列分解成两个规模大致相等的子序列,如果不易解决,再将得到的子序列继续分解,直到子序列中包含的元素个数为1
- 因为单个元素的序列本身是有序的,此时便可以进行合并,从而得到一个完整的有序序列
#include <iostream>
using namespace std;
// 完整的合并
void Merge(int A[], int low, int mid, int high)
{
int* B = new int[high - low + 1]; // 申请一个辅助数组
int i = low, j = mid + 1, k = 0;
while (i <= mid && j <= high) // 按从小到大存放到辅助数组B[]中
{
if (A[i] <= A[j])
B[k++] = A[i++];
else
B[k++] = A[j++];
}
while (i <= mid) B[k++] = A[i++]; // 将数组剩下的元素放置B中
while (j <= high) B[k++] = A[j++];
for (i = low, k = 0; i <= high; i++)
A[i] = B[k++];
delete []B; // 释放空间
}
// 合并排序
/* 采用递归形式
将序列分为两个子序列,然后对子序列进行递归排序,再把两个
已排好的子序列合并成一个有序的序列
*/
void MergeSort(int A[], int low, int high)
{
if (low < high) //将序列一分为二,二分为四,...,直到分成单个元素
{
int mid = (high + low) / 2; //取中点
MergeSort(A, low, mid); //对A[low:mid]中的元素合并排序
MergeSort(A, mid + 1, high); //对A[mid+1:high]中的元素合并排序
Merge(A, low, mid, high);//完整的合并
}
}
int main()
{
int n, A[100];
cout << "请输入数列中的元素个数n为:" << endl;
cin >> n;
cout << "请依次输入数列中的元素:" << endl;
for (int i = 0; i < n; i++)
cin >> A[i];
cout << endl;
MergeSort(A, 0, n - 1);
cout << "合并排序结果:" << endl;
for (int i = 0; i < n; i++)
cout << A[i] << " ";
cout << endl;
return 0;
}
分配排序
- 分配排序不需要比较关键字的大小,根据关键字各位上的值,进行若干趟“分配”和“收集”,实现排序
桶排序
- 将待排序序列划分为划分为若干个空间,每个区间可形象的看做一个桶,如果桶中的记录多于一个,则使用较快的排序方法进行排序,把每个桶中的记录收集起来,最终得到有序序列。