排序之选择排序

简单选择排序

void SelectSort(int arr[],int n)
{
    for(int i=0;i<n-1;i++)//查询数组中每一个位置的最小值,将找到的最小值与目前位置交换
    //只需要查找n-1次,因为只剩下最后一个一定是最大值
    {
        j=SelectMinKey(arr,i,n);
        swap(arr[i],arr[j])
    }
}
void SelectMinKey(int arr[],int k,int n)
{
    int min=arr[k];//将要查找的位置作为初始值,然后将其他的一一与他进行比较,找到其之后最小的那个,返回位置下标
    int pos=k;
    for(int i=k+1;i<n;i++)
    {
        if(arr[i]<min)
        {
            min=arr[i];
            pos=i;
        }
    }
    return pos;
}
总结
  • 比较次数为n(n-1)/2
  • 用树形选择排序进行改进

树形选择排序

说明
  • 减少比较次数
  • 时间复杂度为nlogn
  • 缺点:需要辅助存储空间较多
  • 赢者树:赢得是较小的树,父节点保存较小的节点的下标
void TreeSelectSort(int arr[],int n)
{
//初始化树,创建树并将内容放在终端节点
    int size=2*n-1;//n个点构成一个完全二叉树需要2n-1个树节点
    int *tree=(int *)malloc(sizeof(int)*size);
    int k=size/2;//外部节点的起始下标
    for(int i=0;i<n;i++)
    {
        tree[k++]=arr[i];
    }
    //从最后面的节点开始判断得到最小的值放进根节点
    int curpos=size/2-1;//最后面的第一个分支节点
    Play(tree,size,curpos);
    i=0;
    arr[i]=tree[tree[0]];//得到了第一个最小值
    
    tree[tree[0]]=MAXVALUE;//将他设为最大值,方便找寻第二小的数值
    for(int i=0;i<n;i++)//第一次及记录后得到的数据依旧保存在树中,因此只需要比较其父节点直到根节点即可
    {
        curpos=(tree[0]-1)/2;//最小数值的父节点
        Select(tree,size,curpos);
        arr[i]=tree[tree[0]];//依次得到第二小的数值,第三小的数值
        tree[[tree[0]]=MAXVALUE;
    }
    free(tree);
    tree=NULL;
}
void Play(int tree[],int n,int p)//从最后一个分支节点p开始判断,一一比较其左右子树的大小,
//得到较小的数值的下标放进p中,不断p--直到p为根节点
{
    int left,right;
    int leftvalue,rightvalue;
    while(p>=0)
    {
        left=2*p+1;//p的左子树的下标
        right=2*p+2;//p的右子树的下标
        leftvalue=getvalue(tree,n,left);//p的左子树的真实值
        rightvalue=getvalue(tree,n,right);//p的右子树的真实值
        if(leftvalue<=rightvalue)
        {
            if(left<n/2)//输入内部节点,tree[left]中保存的是下标
            {
                tree[p]=tree[left];
            }
            else
            {
                tree[p]=left;//外部节点,直接将下标保存
            }
        }
        else
        {
            if(right<2/n)
            {
                tree[p]=tree[right];
            }
            else
            {
                tree[p]=right;
            }
        }
        p--;
    }
}
int getvalue(int tree[],int n,int p)
{
    if(p>=n)
        return MAXVALUE;
    int value;
    if(p<n/2)
    {
        value=tree[tree[p]];
    }
    else
    {
        value=tree[p];
    }
}
void Select(int tree[],int n,int p)
{
    int i=p;
    int j=2*p-1;//父节点的左子树
    int leftvalue,rightvalue;
    int falg=-1;
    while(flag&&i>=0)
    {
        leftvalue=getvalue(tree,n,j);//p的左子树的真实值
        rightvalue=getvalue(tree,n,j+1);//p的右子树的真实值
        if(leftvalue<=rightvalue)
        {
            if(j<n/2)//输入内部节点,tree[left]中保存的是下标
            {
                tree[i]=tree[j];
            }
            else
            {
                tree[i]=left;//外部节点,直接将下标保存
            }
        }
        else
        {
            if(j+1<2/n)
            {
                tree[i]=tree[j+1];
            }
            else
            {
                tree[i]=right;
            }
        }
        if(i==0)
            flag++;
        i=(i-1)/2;//找到父节点的父节点
        j=2*i+1;//依旧为新的父节点的左子树
    }
}
总结
  • 树形选择排序先要初始化树,再从最后一个分支开始比较,找到最小的数值,然后只需要比较其父节点即可,将上一次找到的最小值设为最大值就不受影响了
  • 分支节点中保存的不是比较后的数据而保存的是他们在树中的下标

堆排序算法

说明
  • 每一个父节点都大于其子节点成为大堆;每一个父节点都小于其左右子树称为小堆
void HeapSort(int arr[],int n)
{
    int*heap=(int*)malloc(sizeof(int)*n);
    for(int i=0;i<n;i++)
    {
        heap[i]=arr[i];
    }
    int curpos=n/2-1;//找到了最后一个分支节点
    while(curpos>=0)//不断调整堆结构直到根节点
    {
        siftDown(heap,n,curpos);
        curpos--;
    }
    for(int i=0;i<n;i++)
    {
        arr[i]=RemoveMinKey(heap,n-i-1);
    }
}
void RemoveMinKey(int heap[],int n)
{
    int key=heap[0];
    heap[0]=heap[n];
    siftDown(heap,n,0);//删除后调整堆结构,只需要对0及其子树进行调整
    return key;
}
void siftDown(int heap[],int n,int p)//调整了p的子树的堆结构
{
    int i=p;//父节点
    int j=2*i+1;//左子树
    while(j<n)
    {
        if(j<n-1&&heap[j]>heap[j+1])//判断j是不是最后一个节点并且右子树是不是比左子树更小,j永远指向子树中最小的那个
            j++;
        if(heap[i]<=heap[j])
            break;
        else
        {
            swap(heap[i],heap[j]);//在调换之后还要看看有没有改变子树中的堆结构,不断循环再次判断
            i=j;
            j=2*i+1;
        }
    }
    free(p);
    p=NULL;
}
总结
  • 对数据较小时不适合使用
  • 效率高,最高不超过nlogn
  • 所需空间较少
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值