关于排序(待排序数据为数组):
1,堆排序
堆排序的基本单元是对仅仅头结点被改变的大根堆的头节点的重新调整,以此单元将待排序数组调整为一个大根堆,然后将大根堆的头结点依次转移到存储堆的数组的末尾,每转移以此需要重新调整。
在调整单元中,输入的数据仅仅为一个被改变的头结点的大根堆,输出是一个调整过后生成的大根堆。
在调整时,有两个关键值,父节点和其最大的子节点,如果父节点小于这个子节点,那么,交换位置就行,然后将被交换的子节点设为父节点,再次重复这个步骤,直到叶子节点为止。在取最大子节点时需要注意的是,右子节点数组下标比左子节点下标大一,因此要排除访问到非大根堆中的数据,即数组访问越界的情况。
在转移时,完成的是对一个大根堆的排序,所以需要的是一个大根堆,数组形式的。因为大根堆的根节点是整个数组中最大的元素,所以,将这个最大的元素和一个叶子节点进行交换的话,就得到了一个符合调整单元输入的待调整的大根堆,并且得到了原大根堆中的最大值。一般选择的叶子节点为大根堆最右边的一个叶子节点,即数组表示形式的最大的下标,同时,交换之后,数据也自然的依次排好了。
那么如何完成排序功能呢,对于排序这个完整的模块来说,输入当然是一组待排序的数据,一般以数组来说的话。首先从第一个非叶子节点开始,将这个节点以及之后的数据作为一个待调整的大根堆,选择这个起始位置的原因是叶子节点的父节点这个节点自然地满足调整模块 中对输入参数的要求,并且可以向上依次递归。选好参数之后,对其调用调整单元,然后这个参数的上一个索引的数据继续调用调整,类似递归的方式,直到参数第一个数据调用完成为止,这样,整个待排序的数组成为了一个大根堆。接下来就是进行的转移的工作了,对这个大根堆进行排序,很简单。
#define SWAP(a, b) {\
(a) ^= (b); (b) ^= (a); (a) ^= (b);\
}<span style="white-space:pre"></span> // 交换的两个数据的内存地址不能相同
/*****************************************************
* 功能: 大根堆调整
* 参数:
* array: 数组地址
* index: 根下标
* array_num: 数组长度,即从index到array_num下标的数据是要调整的大根堆
* 返回:
* 0
*/
int BigHeap_adjust(int array[], int index, int array_num)
{
int index_child;
for (index_child = index * 2 + 1; index_child < array_num; index_child = index * 2 + 1)
{
if (index_child < array_num - 1 && array[index_child + 1] > array[index_child])
{
index_child++;
}
if (array[index] < array[index_child])
{
SWAP(array[index], array[index_child]);
index = index_child;
}
else
{
break;
}
}
return 0;
}
/************************************************
* 功能: 使用大根堆进行排序,非降序
* 参数:
* array: 数组地址
* array_num: 数组长度
* 返回:
* 0
*/
int sort_BigHeap(int array[], int array_num)
{
int i;
for (i = array_num / 2 - 1; i >= 0; i--)
{
BigHeap_adjust(array, i, array_num);
}
for (i = array_num - 1; i > 0; i--)
{
SWAP(array[0], array[i]);
BigHeap_adjust(array, 0, i);
}
return 0;
}
插入排序,以 数组为例,这个排序方法的基本单元是对一个已有的排好序的数组插入一个数据并且插入后仍然是有序的,对这个单元恰当的重复实现了对一个给定数组的排序功能。
如何插入呢?插入之前必须知道要插入的位置,这个就是有序数组的查找方法了,一般,可以依次查找,也可以用二分法查找,找到一个区间,这个区间包含了这个插入值,然后就可以根据这个区间的位置对数组进行移动,赋值插入,要注意的是边界和相等时的处理。特殊边界需要单独处理,相等需要返回下一个位置值。
如何重复呢?如果没有定一个有序数组,只有一个数据的数组当然可以是认为有序的,它的下一个元素作为插入值,得到一个有两个数据的有序数组,然后下一个再继续插入这个有序数组,直到完成排序。
/************************************************
* 功能: 插入排序,非降序
* 参数:
* array: 数组地址
* index_begin: 需要排序的起始下标
* index_end: 需要排序的末尾下标
* 返回:
* 0
*/
int sort_insert(int array[], int index_begin, int index_end)
{
int key; // 暂存要插入的值
int i, j; // i用于记录重复插入时的插入值的数组下标,j用于记录待比较值的下标,每次重复最终j会记录恰好小于key的元素下标,key将插入原j+1处
for (i = index_begin; i <= index_end; i++)
{
key = array[i];
j = i - 1;
while (j >= 0 && key < array[j])
{
array[j + 1] = array[j];
j--;
}
array[j + 1] = key;
}
return 0;
}