选择排序

6 篇文章 0 订阅
2 篇文章 0 订阅

选择排序

简单选择排序

算法思想:第一趟从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;              //处理数值最大的结点
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

siyan985

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值