数据结构与算法导论第七章理论知识(上)

排好序的一:插入排序

void insertsort(int m[],unsigned size)
{
    int j;
    int i;
    for(i=0;i!=size;++i)
        {
            int key=m[i];
            for(j=i;j>=0;--j)
            {
                if(key<=m[j-1])
                    m[j]=m[j-1];
                else
                    break;
            }
            m[j]=k;
        }
}

算法的时间复杂度分析:该算法是消除逆序数类的算法,给定一个大小为n的排序,将他逆序,则两个排序总的逆序数为1+2+3+4+……………………+(N-1)=N(N-1)/2=(N^2-N)/2
交换次数就为上述结果,每次交换时间为1,则总时间为O(N^2)

二:希尔算法

对于一串有序数k1,k2,k3,k4,k5……,其中k1必须为1,且最大数小于排列个数的一种算法

这串数没个人都可以提出自己的排列,最初提出这个算法的人用的是1,2,4,8……2^k这一串有序数
例程如下

void shellsort(int m[],int size)
{
    int i=size/2;
    int x,y;
    while(i!=0)
    {
        for(x=i;x!=size;++x)
        {
            for(y=x;y>=i;y=y-i)
            {
                int key=m[x];
                if(key<=m[y-i])
                    m[y]=m[y-i];
                else
                    break;
            }
            m[y]=key;
        }
        i/=2;
    }
}

最好情况分析:如果输入是排好序的,则每次循环什么也不做,时间复杂度为O(N)
最坏情况分析:有一个坏数组1,9,2,10,3,11,4,12,5,13,6,14,7,15,8,16,则对于k1=1之外的所有k2,k3,k4……什么都不会做,故就类似于插入排序,故时间复杂度为O(N^2)
平均情况分析:太复杂,而且里面用到的数学公式也很复杂,暂时还未看懂如何推导的

三:堆排序

首先二话不说,上代码

void percdown(elements[],int i,int n)//将elements数组的第i项下滤
{
    int key=elements[i];
    int child;
    while(2i+1<n)
    {
        child=2i+1;
        if(child!=n-1&&elements[child]<elements[child+1])
            child++;
        if(key<elements[child])
        {
            elements[i]=elements[child];
            i=child;
        }
        else
            break;          
    }   
    elements[i]=key;
}
void headsort(elements[],int size)
{
    for(int i=size/2;i>=0;--i)
    {
        percdown(elements[],i,size);
    }
    for(int i=n-1;i>0;--i)
    {
        swap(&elemens[0],&elements[i]);
        percdown(elements,0,i);
    }
}

算法分析
平均交换次数为NlogN-O(N)具体证明我还是没看懂,很尴尬
但我知一开始构造对的时间复杂度=N
构造堆的比较次数即为该堆的高度之和
有下面定理
2^(b+1)-1个节点的高度为b的二叉树的高度之和为2^(b+1)-1-(b+1)
该定理的证明用等比数列求和即可证出

三:分治排序
代码如下

void dividesort(int m[], int n[], int left, int right)//多添加一个n数组来保存合并后的数组否则在merge中需要重复的开空间删空间,会浪费时间
{
    if (left >= right)//?
        return;//?
    else
    {
        int center = (left + right) / 2;
        dividesort(m, n, left, center);
        dividesort(m, n, center + 1, right);
        mergesort(m, n, left, center, right);
    }
}

void mergesort(int m[], int n[],int left, int center, int right)//我所用的是分类讨论写法,还有一种写法为设置哨兵写法
{
    int x = left;
    int y = center + 1;
    int i = left;
    while (x <= center&&y <= right)
    {
        if (m[x] < m[y])
        {
            n[i] = m[x];
            ++i;
        }
        else
        {
            n[i] = m[y];
            ++i;
        }
    }
    while (x <= center)
        n[i++] = m[x++];
    while (y <= right)
        n[i++] = m[y++];
    for (int j = left; j <= right; ++j)
        m[j] = n[j];

}

算法分析
T(1)=1
T(N)=2T(N/2)+N
T(N)/N=T(N/2)/(N/2)+1
根据叠缩求和就可求出
T(N)=NlogN+N
另一种方法可以用画树的方法,这里不方便画出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值