排序
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
排序将一组数据序列重新排列,使得数据元素序列按照某个关键字有序。
提示:以下是本篇文章正文内容,下面案例可供参考
一、排序的基本概念
-
若关键字值不重复,排出的结果都唯一。
-
.稳定排序与不稳定排序 。排序后相同关键字的相对位置不变为稳定排序,相对位置改变则为不稳定排序。
e.g. 3,2,*3,4.
稳定排序:2,3,*3,4;
不稳定排序:2,*3,3,4; -
内排序与外排序。根据是否需要访问外存(硬盘)来区分。
二、插入排序
1.算法实现:
- 取值
- 挤空
- 插入
template<typename T>
void insertionSort(vector<T>& a)
{
int j;
for (int p = 0; p < a.size(); p++)
{
T tmp = a[p];
for (j=p; j >0&&tmp<a[j-1]; j--)
{
a[j] = a[j - 1];
}
a[j] = tmp;
}
}
2. C++STL库实现
代码如下(示例):
三.希尔排序(shell’s sort)
分割成若干个较小的子文件,对子文件分别进行直接插入排序,当文件达到基本有序时,再对整个文件进行一次直接插入排序。
- 先进行宏观调整
- 再做微观调整
四.选择排序
排序过程:
- 首先通过n-1次关键字比较,从n个记录中找出关键字最小的记录,与第一个记录进行交换。
- 再通过n-2次比较,从剩余的n-1个记录中找出次小的记录,与第二个记录交换
- 重复操作,共进行n-1趟排序。
算法实现
template<typename T>
void smp_selectSort(vector<T>& a, n)
{
int i, j, k;
for ( i = 0; i < n; i++)
{
k = i;
T x;
for (j = i, j < n, j++)
{
if (a[j]<a[k])
k = j;
}
if (i!=k)
x = a[i];
a[i] = a[k];
a[k] = x;
}
}
算法评价:
时间复杂度:T(n)=O(n^2)
空间复杂度:S(n)=O(1)
非稳定排序
五.归并排序
归并排序:将两个及以上的有序表组合成一个新的有序表
二路归并排序:二分法得到多个有序子序列,将其两两归并排序,重复得到完整的排序。如果某一趟归并过程中,排序数不是对应的,可能出现单个表的情况,轮空直接将其复制到下一轮的排序中。
template<typename T>
void mergeSort(vector<T>& a)//驱动例程
{
vector<T> tmpArray(a.size());
mergeSort(a, tmpArray, 0, a.size() - 1);
}
template<typename T>
void mergeSort(vector<T>& a, vector<T>& tmpArray, int left, int right)
{
if (left<right)
{
int center = (left + right) / 2;
mergeSort(a, tmpArray, left, center);
mergeSort(a, tmpArray, center + 1, right);
merge(a, tmpArray, left, center + 1, right);
}
}
template<typename T>
void merge(vector<T>& A, vector<T>& tmpArray, int leftPos, int rightPos, int rightEnd)
{
int leftEnd = rightPos - 1;
int tmpPos = leftPos;
int numElements = rightEnd - leftPods + 1;
while (leftPods<=leftEnd&&rightPos<=rightEnd)
{
if (a[leftPods]<=a[rightPods])
tmeArray[tmpPos++] = a[leftPods++];
else
tmeArray[tmpPos++] = a[rightPods++];
}
while (leftPods<=leftEnd)
tmpArray[tmpPods++] = a[leftPods++];
while (rightPods <= rightEnd)
tmpArray[tmpPods++] = a[rightPods++];
for (int i = 0; i < numElements; i++,rightEnd--)
{
a[rightEnd] = tmpArray[rightEnd];
}
}
算法评价:
时间复杂度:O(nlogn)
空间复杂度:O(n)
归并排序是稳定排序
六.交换排序
通过交换无序序列中的关键字得到其中关键字最小或最大的记录,再将其加入到有序子序列中。
- 冒泡排序·
- 快速排序
1.冒泡排序
将第一个记录和第二个记录进行比较,若为逆序则交换,以此类推第二个和第三个交换。第一次冒泡过程后,最大的记录就会排在末尾。之后再对前面n-1个记录进行排序。重复上述过程直到没有交换为止。
template<typename T>
void bubble_sort(T r[], int n)
{
int i, j, flag=1;
T x;
m = n;
while ((m>1)&&(flag==1))
{
flag = 0;
for ( j = 0; j < m; j++)
{
if (r[j] > r[j + 1])
{
flag=1;
x = r[j];
r[j] = r[j + 1];
r[j + 1] = x;
}
m--;
}
}
}
2.快速排序
实际使用中已知的最快的算法
- 选取合适的枢纽
- 将关键字小于枢纽的记录放到枢纽前面,将关键字大于枢纽的记录放到枢纽的后面。
- 以此类推多次重复排序。
以下为三者取中法找枢纽的快速排序法。
template<typename T>
void qk_sort(T r[], int t, int w)
{
int i, j, k;
T x;
T aux;
if (t >= w)
return;
i = t, j = w;
x=fmin(r[i], r[j], r[(i + j) / 2]);
aux = r[j];
r[j] = x;
fmin(r[i], r[j], r[(i + j) / 2]) = aux;
j = w - 1;
while (i<j)
{
while (r[i]<x)
i++;
while (r[j]>x)
j--;
if (r[j]<x)
{
aux = r[i];
r[i] = r[j];
r[j] = aux;
}
}
}
八.基数排序
对具有多个关键字的记录进行排序。
分为高位优先多关键字排序和低优先位关键字排序
以低优先级排序为例:
int maxbit(int data[], int n) //辅助函数,求数据的最大位数
{
int d = 1; //保存最大的位数
int p = 10;
for(int i = 0; i < n; ++i)
{
while(data[i] >= p)
{
p *= 10;
++d;
}
}
return d;
}
void radixsort(int data[], int n) //基数排序
{
int d = maxbit(data, n);
int *tmp = newint[n];
int *count = newint[10]; //计数器
int i, j, k;
int radix = 1;
for(i = 1; i <= d; i++) //进行d次排序
{
for(j = 0; j < 10; j++)
count[j] = 0; //每次分配前清空计数器
for(j = 0; j < n; j++)
{
k = (data[j] / radix) % 10; //统计每个桶中的记录数
count[k]++;
}
for(j = 1; j < 10; j++)
count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶
for(j = n - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中
{
k = (data[j] / radix) % 10;
tmp[count[k] - 1] = data[j];
count[k]--;
}
for(j = 0; j < n; j++) //将临时数组的内容复制到data中
data[j] = tmp[j];
radix = radix * 10;
}
delete[]tmp;
delete[]count;
}
九.外部排序
外排序模型
预处理
归并