文章目录
0. 排序基本概念
- 定义:整理文件的记录次序,使其按关键码递增(或递减)次序进行排列。
- 稳定性:多个关键吗星通的记录,经过排序后,这些具有相同关键码记录之间的相对次序保持不变,则称排序是稳定的
- 原地排序:不需要额外的空间(允许少量空间)进行排序
1. 插入排序
定义:将待排序的记录,按其关键码的大小插入到已经排好序的有序子表中,直至全部插入完成为止。
1.1 直接插入排序
一次将记录序列中的每一个记录插入到有序段中,使有序段的长度不断扩大,最初的有序段为第一个元素本身。
void InsertSort(int s[],int len)
{
for (int i = 1; i < len; i++)
{
int j, tmp = s[i];
for (j = i - 1; j >= 0; j--)
{
if (tmp < s[j])
s[j + 1] = s[j];
else break;
}
s[j + 1] = tmp;
}
}
1.2 二分插入排序
- 前提是对有序表插入
- 先二分查找找到插入的位置
- 再将后面的元素后移,留出空位
- 插入
1.3 表插入排序
- 不移动记录的情况下排序
- 通过移动指针进行排序
- 在插入第 i 个记录 Ri 时,R1,R2,R3,……Ri-1 已经通过各自的指针排好序了,然后依次比较找到合适的位置插入
1.4 希尔排序(缩小增量排序)
算法思想:将待排序的记录分成几组,从而减少参与直接插入排序的数据量,当经过几次分组排序后,记录的排列已经基本有序了,这个时候在对所有的记录实施直接插入排序。
void ShellSort( ElementType A[], int N )
{ /* 希尔排序 - 用Sedgewick增量序列 */
int Si, D, P, i;
ElementType Tmp;
/* 这里只列出一小部分增量 */
int Sedgewick[] = {929, 505, 209, 109, 41, 19, 5, 1, 0};
for ( Si=0; Sedgewick[Si]>=N; Si++ )
; /* 初始的增量Sedgewick[Si]不能超过待排序列长度 */
for ( D=Sedgewick[Si]; D>0; D=Sedgewick[++Si] )
for ( P=D; P<N; P++ ) { /* 插入排序*/
Tmp = A[P];
for ( i=P; i>=D && A[i-D]>Tmp; i-=D )
A[i] = A[i-D];
A[i] = Tmp;
}
}
2. 交换排序
算法思想:将待排序记录的关键码进行两两比较,发现两个记录次序相反时就进行交换,知道没有相反记录为止
2.1 冒泡排序
算法思想:对所有相邻记录的关键码值进行比较,如果是逆序,则交换,重复这个过程直至整个序列有序
void BubSort(int s[], int len)
{
bool tmp = false; //记录是否交换
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - 1; j++)
{
if (s[j] > s[j + 1])
{
swap(s[j], s[j + 1]);
tmp = true;
}
}
if (tmp)
tmp = false;
else break;
}
}
2.2 快速排序
算法思想:首先将待排序记录序列中所有记录作为当前待排序区域,选取第一个记录的关键码值为基准(轴值),从待排序记录序列左右两端向中间靠拢,交替与轴值比较,若左侧记录大于轴值,则将该纪录移到基准记录右侧,若右侧记录小于轴值,则将该记录移到基准记录左侧,至此,基准记录将待排序记录分为左右两块,左侧的所有记录小于基准记录,右侧的所有记录大于基准记录,这就是一趟快速排序,然后再堆左右两个区域进行快速排序,重复这个过程直至每个区域只含有一个记录,这时整个序列有序
int qSort(int s[], int L, int R)
{
int piv = L;
int p = s[piv];
for (int i = L + 1; i <= R; i++)
{
if (s[i] < s[piv])
{
piv++;
if (i != piv)
swap(s[i], s[piv]);
}
}
s[L] = s[piv];
s[piv] = p;
return piv;
}
void QSort(int s[], int L,int R)
{
if (L < R)
{
int piv = qSort(s, L, R);
QSort(s, L, piv - 1);
QSort(s, piv + 1, R);
}
}
void QuickSort(int s[], int len)
{
QSort(s, 0, len - 1);
}
3. 选择排序
算法思想:每一次从待排序的记录中选出最小的。放在已排序的子序列后面,直至序列有序
3.1 线性选择排序
算法思想:新建一个空间,从未排序的序列中找到最小的,放在新的空间内,重复这个过程直至未排序的序列为空
3.2 交换线性选择排序
算法思想:将序列分为有序区域和无序区域,初始时有序区域为空,将无序序列中最小与无序区域后第一个元素交换,重复这个过程直至无序序列为空
void SelectSort(int s[], int len)
{
for (int i = 0; i < len - 1; i++)
{
int min = s[i];
for (int j = i+1; j < len; j++)
{
if (s[min] > s[j])
min = j;
}
swap(s[min], s[i]);
}
}
3.3 堆排序
算法思想:将所有元素建堆,建好以后不断弹出堆顶元素,放入序列末尾(初始序列为空),直至堆为空,此时序列有序
void HeapSort(vector<int>& s, int len)
{
priority_queue<int> heap;
for (int i = 0; i < len; i++)
heap.push(s[i]);
for (int i = len - 1; i >= 0; i--)
{
s[i] = heap.top();
heap.pop();
}
}
4. 归并排序
算法思想:利用“归并”进行排序,将n个待排序的序列看作n个长度为1的有序序列,两两归并得到【n/2】个有序序列。重复这个过程直至有序序列个数为1.
void MergeTwo(int s[], int L, int midR, int R,int n[]) //合并两部分
{
for (int i = L, j = midR + 1,l=L; l<=R;l++)
{
if (i<=midR&&s[i] < s[j])
{
n[l] = s[i];
i++;
}
else {
n[l] = s[j];
j++;
}
}
for (int i = L; i <= R; i++)
s[i] = n[i];
}
void MSort(int s[],int L,int R,int n[])
{
if (L < R)
{
MSort(s, L, (L + R) / 2,n); //对左半部分排序
MSort(s, (L + R) / 2+1,R ,n); //对右半部分排序
MergeTwo(s, L, (L + R) / 2, R,n); //合并两部分
}
}
void MergeSort(int s[],int len)
{
if (len > 1)
{
int* n = new int[len] {};
MSort(s, 0, len - 1,n);
delete[] n;
}
}
5. 基数排序
算法思想:基于关键词的性质进行排序
5.1 多键排序
有多个关键词进行排序
- 最高位优先 MSD
先对主关键码进行排序,将序列分为若干个子序列,在子序列中对次一级的关键码排序,重复这个过程到没有关键码用完。然后从优先级最低L级的关键字开始排序,把所有L+1级关键码相同的子序列排序,重复这个过程直至所有子序列连接在一起。 - 最低位优先 LSD
与上面的的优先级顺序相反
5.2 桶排序
算法思想:设置若干个桶,依次扫描待排序序列,将键值相等的记录放在同一个桶里,然后依次连接各个桶。
5.3 链式基数排序
算法思想:最主要的是拆键,将一个键拆成多个键,比如512这个数拆分为5 , 1 , 2 三个键,然后用低位优先的多键排序,顺序是 2 -->1 -->5 如此如此即可
6. 其他排序
6.1 二叉树排序法
- 建立二叉树
- 中序遍历二叉树
6.2 计数排序法
和冒泡排序很像,但不需要交换,需要额外的空间存储计数数组
void CSort(int s[], int len) //计数排序
{
int* num = new int[len] {};//建立计数数组
for (int i = 0; i < len-1; i++) //循环与后面的数比较
{
for (int j = i + 1; j < len;j++)
{
if (s[i] < s[j]) //较大的数计数器+1
num[j]++;
else num[i]++;
}
}
}
7.各种内排序比较
8. 外排序
8.1 自然归并排序法
- 扫描一遍原始数据
- 将初始有序的子序列归并得到有序序列
8.2 k路归并法
将k个归并段归并为一个大的归并段(零头除外)
8.3 多段归并法
每次将有序段最小的磁带与其他磁带中有相同数目的有序段作k路归并,然后将结果写入空白磁带上,重复直至归并为一个有序序列为止