选择排序
简单选择排序
算法思想:第一趟从n个元素的数据序列中选出关键字最小/大的元素并放在最前/后位置,下一趟从n-1个元素中选出最小/大的元素并放在最前/后的下一个位置。以此类推,经过n-1趟完成排序。
可能有人会把选择排序与冒泡排序弄混,百度百科解释 "择排序法 是对 定位比较交换法(也就是冒泡排序法) 的一种改进。",
其实二者最大的差别就是比较的次数,冒泡排序法是如果当前元素比下一个元素大(升序),则两个数交换.而简单选择算法是先找到整个待排序列中最小的,然后与待排序列中第一个元素交换,每次只交换一次.
int SelectMinKey(int L[],int n){
//选择最小数,从n开始
int min = n;
int mi;
mi = L[n];
for(int i = n+1;i <= 9; ++i){
if(L[i] < mi) {
mi = L[i]; //get minimum value
min = i; //get minimum position
}//endif
}//endfor
return min;
}
void SelectSort(int L[]){
int j;
int t;
for(int i = 1;i <= 9; ++i){
j = SelectMinKey(L,i);
//在L[i]~L[L.length]中选择最小的记录并将其地址赋值给j
if(i != j) {
t = L[i];
L[i] = L[j];
L[j] = t;
}//endif
}//endfor
}
堆排序
堆是一个完全二叉树,任何一个非叶子结点的值都不大于(不小于)其左右孩子的值.叫小顶堆(大顶堆).
操作过程:
1.创建堆
输入数据是49 38 65 97 76 13 27 49
2.调整堆,使其满足堆的定义
3.取出最大值(最小值),重新调整堆
取出最大值,将待排序列最后的数放在堆顶,重新调整堆...重复上述步骤知道只剩下一个元素为止
void HeapAdjust(int L[],int s,int m){
//对顺序表做查找,从值最大的孩子结点向下筛选,找到最大值
//每次只对一个元素rc进行操作,使其所在子树满足堆的定义
//把s到m的元素进行调整
int rc = L[s];
for(int j = 2*s;j <= m;j *= 2){
//2*s是L[s]的左子结点,每次乘2就找到左孩子的左孩子
//找到s结点的最大的子结点
if(j < m && L[j] <= L[j+1]) {
//j<m是判断的元素在所有元素内,因为只有m个元素
//L[j] <= L[j+1]是找到子节点中最大的
j++;
}//endif
//L[j]是rc子结点中最大的
if(rc > L[j]) break;//如果rc最大则退出while
L[s] = L[j]; //子节点比父节点大,将子节点放在父节点的位置
s = j; //s是rc目前的位置
}//endfor
L[s] = rc; //把rc放在正确的位置
}
void HeapSort(int L[]){
//对顺序表L进行堆排序
int value;
//初始化堆,将待排序序列构造成堆
for(int i = L.length/2;i > 0;i--){
//调整所有非叶子节点
//9/2是初始堆的最后一个非叶子结点
HeapAdjust(L,i,L.length);
}//endfor
for(i = L.length;i > 1; --i){
//数列中最后一个元素与第一个元素交换
value = L[1];
L[1] = L[i];
L[i] = value;
//待排序序列数量减一,有序的数在原始数列尾部
HeapAdjust(L,1,i-1);//将L[1...i-1]重新调整为大顶堆
}//endfor
}
树形排序
将输入的待排序数据构建成满二叉树,必须是满二叉树
,两两比较选择最小的作为父结点,以此类推构造满二叉树,根节点就是最小的结点,此节点有序,将叶子结点中的此结点设置为无穷大(之后不再比较),不断迭代比较完所有结点.
//树形选择排序
template <class T>
class TreeNode {
public:
T data; //结点数据值
int index;//树中位置
int active;//是否继续比较
TreeNode<T>& operator= (TreeNode<T>& treenode){
this->data = treenode.data;
this->index = treenode.index;
this->active = treenode.active;
return *this;
}
};
//树形选择排序
template <class T>
void ChangeTree(TreeNode<T> *tree,int i){
if (i % 2 == 0) {
tree[(i-1)/2] = tree[i-1]; //当i为偶数时把左结点赋给父节点
} else {
tree[(i-1)/2] = tree[i+1]; //当i为奇数时把右结点比较父结点
}
int j;
i = (i-1)/2; //i指向已排序结点的父结点
while(i){
if (i % 2 == 0) {
//i 是偶数代表i指向右孩子,所以j指向其前一个
j = i - 1;
} else {
j = i + 1;
}
if (!tree[i].active || !tree[j].active) {
//两个同级兄弟结点中有一个是可比较(未排序的)
//tree[i]未排序
if (tree[i].active) {
//把tree[i]赋给其父结点
tree[(i-1)/2] = tree[i];
} else {
tree[(i-1)/2] = tree[j];
}
} else {
//两个结点都已有序,按照值的大小将小的赋给父结点
if (tree[i].data < tree[j].data) {
tree[(i-1)/2] = tree[i];
} else {
tree[(i-1)/2] = tree[j];
}
}
i = (i-1)/2;//i指向上一层,这里只调整参数i位置所在的子树
}//endwhile
}
int Power(int n){
//计算2的n次方
int result = 1;
if (n >= 1) {
for(int i = 1;i <= n; ++i){
result *= 2;
}//endfor
return result;
} else {
return 1;
}
}
int LeapNum(int n){
//满二叉树的叶子结点总数(>=n)
for(int i = 1;i < 100; ++i){
//Power(i-1)是第i行结点的数量
if (Power(i-1) < n && n < Power(i)) {
//n大于i层的数量小于i+1层的结点数,返回结点数最大的层
return Power(i);
} else if(Power(i-1) == n){
//返回结点等于n的层的结点数
return Power(i-1);
}
}//endfor
}
template <class T>
void TreeSort(T a[],int n){
int bottomSize = LeapNum(n); //树底层结点个数,此处必须满足满二叉树
int size = 2*bottomSize - 1; //树中结点总数
int externalIndex = bottomSize - 1; //开始比较的结点位置,一共有externalIndex个内部结点
TreeNode<T> *tree;
tree = new TreeNode<T>[size];
int i,j = 0;
//将待排序结点放在树的后n个节点中
//tree[]的后n个位置存放a[]的元素值
for(i = externalIndex;i < size; ++i){
tree[i].index = i;
if (j < n) {//共有n个数
tree[i].active = 1;
tree[i].data = a[j++];
} else {
//将结点tree[i]赋值为无穷大,即已经比较过了
tree[i].active = 0;
}
}//endfor
//比较找到最小结点
i = externalIndex;
while(i){
j = i;
while(j < 2*i){
//2*i is the last node in this layer, while statement traverse the whole layer
if(!tree[j+1].active || tree[j].data <= tree[j+1].data) {
//当前结点小于其右兄弟或者其右兄弟不必在比较
if(!tree[j+1].active && !tree[j].active) {
//tree[(j-1/2)] is the parent of tree[j]
tree[(j-1)/2].active = 0; //这两个结点不用比较了
}//endif
tree[(j-1)/2] = tree[j]; //较小结点(leftNode)赋值给其双亲结点,结点包括index,data and active
} else {
tree[(j-1)/2] = tree[j+1]; //rightNode assign to parentNode
}
//每次比较两个结点
j += 2;
}//endwhile
i = (i-1)/2; //i point to the first element in parent layer
}//整个树已经建立完成,根节点是最小的结点
for(i = 0;i < n-1; ++i){ //处理前n-1个结点
a[i] = tree[0].data;
tree[tree[0].index].active = 0; //树中子节点第tree[0].index不再参加比较
ChangeTree(tree,tree[0].index); //修改树结构
}//endfor
a[n-1] = tree[0].data; //处理数值最大的结点
}