基于抽象数据类型的几种算法实现

复制

void copyFrom(T* const A, Rank lo, Rank hi)
{
    _elem = new T[_capacity = 2*(hi - lo)]; //分配空间
    _size = 0; //规模清零
    while(lo < hi)
        _elem[_size++] = A[lo++];
}

这里:开辟了内部数组_elem_[],capacity代表总容量,_size代表当前实际的规模。

扩容

void expand()
{
    if(_size < _capacity) return; //未满员,不必扩容
    _capacity = max(_capacity, DEFAULT_CAPACITY);
    T* oldElem = _elem; _elem = new T[_capacity*2]; //容量加倍,T为基本类型
    for (int i = 0; i< _size; i++)
    _elem[i] = oldElem[i];
    delete [] oldElem; //释放原空间
}

容量加倍有时候未免太过浪费空间,这里可以改进为容量递增策略:

T* old Elem = _elem; _elem = new T[_capacity += INCREMENT] //追加固定的大小容量

插入

insert(Rank r, T const &e)
{
    expand(); //若有必要,扩容
    for (int i = _size; i >r ;i--)//自后向前
        _elem[i] = _elem[i-1];//后继元素顺次后移一个单元
     _elem[r] = e; //植入新元素,更新容量
     _size++;  //更新容量
     return r; //返回插入元素的下标
}

区间删除

remove(Rank lo, Rank hi)
{
    if(lo == hi) return 0;
    while(hi < _size) _elem[lo++] = _elem[hi++] // [hi, _size)顺次前移hi-lo位
    _size = lo; shrink(); //更新规模,有必要则缩容
    return hi - lo; //返回被删除元素数目
}

查找

find(T const &e, Rank lo,Rank hi
{
    while((lo < hi--)&&(e != _elem[hi])); //逆向查找
    return hi;  
}

单元素删除

remove(Rank r)
{
    T e = _elem[r]; //备份被删除元素 
    remove(r,r+1); //调用区间删除 
    return e; //返回被删除元素
}

唯一化

这里给出的实现均在有序情况下

两种低效版本:

第一种:

deduplicate()
{
    int oldSize = _size;
    Rank i = 1;
    while(i < _size)
        (find(_elem[i],0,i) < 0)? i++  //无雷同继续考察后继
         : remove(i); 
         return oldSize - _size; //返回删除元素总数
}

第二种:

deduplicate()
{
    int oldSize = _size;
    Rank i = 1;
    while(i < _size - 1)
        (_elem[i] == _elem[i+1])? remove(i+1)  //无雷同继续考察后继
         : i++; 
         return oldSize - _size; //返回删除元素总数
}

低效的原因在于,同一元素可作为被删除元素的后继多次前移。

高效版:

uniquify()
{
    Rank i = 0, j = 0;
    while(++j < _size)
        if(_elem[i] != _elem[j]) _elem[++i] = _elem[j];  //发现不同元素,前移至紧邻与前者右侧
        _size = ++i;
        return j - i;
}

二分查找

版本A :

binSearch(T* A, T const& e, Rank lo, Rank hi)
{
    while(lo < hi)
    {
        Rank mi = (lo + hi)/2;
        if(e < A[mi]) hi = mi;
        else (e > A[mi]) lo = mi + 1;
        else return mi;
    }
    return -1; //查找失败
}


简明的返回 -1,实际如果原对象中存在多个查找目标原宿,是不够准确的。

版本B:

binSearch(T* A, T const& e, Rank lo, Rank hi)
{
    while(1 < hi - lo) //有效查找区间缩短至1时,算法终止
    {
        Rank mi = (lo + hi)/2;
        (e < A[mi])? hi = mi : lo = mi; //[lo,mi)或[mi,hi)
    } //出口 hi = lo + 1
    return (e == A[lo] ? lo : -1)
}

版本C:

binSearch(T* A, T const& e, Rank lo, Rank hi)
{
    while(lo < hi)
    {
        Rank mi = (lo + hi)/2;
        (e < A[mi]) ? hi = mi : lo = mi + 1; //[lo,mi)或(mi,hi)
    }//出口A[lo = hi]为大于e的最小元素
    return --lo;//lo - 1为不大于e的元素的下标
}

二分查找的最佳时利用黄金比例切分。可用斐波那契查找实现。

冒泡排序

版本A:

bubbleSort(Rank lo, Rank hi){
    while(!bubble(lo, hi--));
    }
bubble(Rank lo, Rank hi)
{
    bool sorted = ture; //整体有序标志
    while(++lo < hi)  //逐个检查各对相邻元素
    {
        if(_elem[lo - 1] > _elem[lo])
        {
            sorted = false; //逆序,整体未有序,false表示
            swap(_elem[lo - 1], _elem[lo]);
        }
    }
    return sorted;
}

这里主要针对传入的是有序情况下的过滤。

版本B:

bubbleSort(Rank lo, Rank hi){
    while(lo < (hi = bubble(lo, hi))); //逐趟扫描,直至全序
}
bubble(Rank lo, Rank hi)
{
    Rank last = lo;
    while(++lo < hi)  //至左向右,逐一检查相邻元素
    {
        if(_elem[lo - 1] > _elem[lo])
        {
            last = lo; //更新最右侧逆序对位置记录
            swap(_elem[lo - 1], _elem[lo]);
        }
    }
    return last;
}

这里把传入的数组中每段有序的区间的过滤。

©️2020 CSDN 皮肤主题: 技术工厂 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值