数据结构中的排序
文章目录
一、排序的基本术语
1.内部排序:
数据量不大,数据在内存,无需内外存交换数据。
2.外部排序
数据量较大,文件需要外存(如硬盘上的文件排序),外排序远比内排序复杂。
3.排序的稳定性
举个例子:如49,97,76,13,27,49’
稳定排序之后:13,27,49,49’,76,97
不稳定排序之后:13,27,49’,49,76,97
稳定排序在只对结构体(有多种因素影响排序结果)有意义。
二、顺序表
1.顺序表的存储结构
typedef int KeyType; //定义关键字类型为int
typedef char InfoType; //数据项为字符型
typedef struct
{
KeyType key; //关键字项
InfoType data; //其他数据项,类型为InfoType
} RecType; //查找元素的类型
2.操作顺序表的方法
//交换表中的数据项x和y
void swap(RecType x, RecType y)
{
RecType tmp = x; //采取定义第三方变量的方法
x = y; y = tmp;
}
//创建顺序表
void CreateList(RecType R[], KeyType keys[], int n)
{
for (int i = 0; i < n; i++) //将字符数组对应赋值对应数据项,R[]为空,利用关键字进行排序运算
R[i].key = keys[i]; //将除留余数法得到数组对应赋值关键字数组
}
//输出顺序表
void DispList(RecType R[], int n)
{
for (int i = 0; i < n; i++)
printf("%d ", R[i].key);
printf("\n");
}
三、快速排序
1.原理
如图所示,每一次以第一个元素为基准
其实快速排序就是三叉树形式,每次都对数组进行截三段,直到每个元素都成叶子。
2.算法
划分算法,一次划分数组为三块
//一趟划分
int partition(RecType R[], int s, int t)
{
int i = s, j = t;
RecType tmp = R[i]; //以R[i]为基准,一般s为0
while (i < j) //从两端交替向中间扫描,直至i=j为止
{
while (j > i && R[j].key >= tmp.key)
j--; //从右向左扫描,找一个小于tmp.key的R[j]
R[i] = R[j]; //找到这样的R[j],放入R[i]处
while (i < j && R[i].key <= tmp.key)
i++; //从左向右扫描,找一个大于tmp.key的R[i]
R[j] = R[i]; //找到这样的R[i],放入R[j]处
}
R[i] = tmp;
return i;
}
主算法
void QuickSort(RecType R[], int s, int t) //对R[s..t]的元素进行快速排序
{
int i;
RecType tmp;
if (s < t) //区间内至少存在两个元素的情况
{
i = partition(R, s, t);
QuickSort(R, s, i - 1); //对左区间递归排序
QuickSort(R, i + 1, t); //对右区间递归排序
}
}
3.算法性能分析
数据移动次数太多,数据量较少时比较合适
四、堆排序
1.原理
(1)其实堆排序最终将无序数组调整成一个有序完全二叉树,根据从大小顺序分为小根堆、大根堆,这里主要讨论小根堆。主要有筛选与调整两个过程
(2)筛选:每次从数组元素中取最小元素作为根,一般左比右小,上肯定比下小,多次递归,建成完全二叉树。
(3)调整:输出根后以最后一个元素代替它。
2.算法
筛选过程
void sift(RecType R[], int low, int high)
{
int i = low, j = 2 * i; //R[j]是R[i]的左孩子
RecType temp = R[i];
while (j <= high)
{
if (j < high && R[j].key < R[j + 1].key) //若右孩子较大,把j指向右孩子
j++; //变为2i+1
if (temp.key < R[j].key)
{
R[i] = R[j]; //将R[j]调整到双亲结点位置上
i = j; //修改i和j值,以便继续向下筛选
j = 2 * i;
}
else break; //筛选结束
}
R[i] = temp; //被筛选结点的值放入最终位置
}
调整过程
void HeapSort(RecType R[], int n)
{
int i;
RecType tmp;
for (i = n / 2; i >= 1; i--) //循环建立初始堆,调用sift算法 n/2 次
sift(R, i, n);
for (i = n; i >= 2; i--) //进行n-1趟完成推排序,每一趟堆排序的元素个数减1
{
tmp = R[1]; //将最后一个元素与根R[1]交换
R[1] = R[i];
R[i] = tmp;
sift(R, 1, i - 1); //对R[1..i-1]进行筛选,得到i-1个节点的堆
}
}
3.算法性能分析
堆排序时间稳定,但是不稳定排序。