算法导论 练习14.1-7

14.1-7 说明如何在 O ( n l g n ) O(nlgn) O(nlgn)时间内,利用顺序统计树对大小为 n n n的数组中的逆序对(见思考题2-4)进行计树。

这道题和算法导思考题2-4一致,当时采用了归并排序和线段树进行解决,在另外一篇博客中给出了题解。算法导论 思考题2-4

这里我们将采用书中的顺序统计树(order-statistic tree)来解决。其实本质上和线段树类似,都是采用一种支持 O ( l g n ) O(lgn) O(lgn)操作的数据结构,来进行统计,思考题2-4的线段树采用统计区间内数字的次数。而顺序统计树,通过记录树的大小,从而快速得出对应关键字的秩。

采用顺序统计树这里有两种方法得出逆序对。

对于数组 A [ 5 ] = ( 5 , 4 , 3 , 2 , 1 ) A[5]=(5,4,3,2,1) A[5]=(5,4,3,2,1)。我们要求其逆序对,只需要计算对于数组中的每个数 A [ i ] A[i] A[i],计算 A [ 1 ] → A [ i − 1 ] A[1]\rightarrow A[i-1] A[1]A[i1]之中大于 A [ i ] A[i] A[i]的个数。我们可以采用插入排序排序来计算逆序对,逆序对等于每个数 A [ i ] A[i] A[i]在与 A [ 1 ] → A [ i − 1 ] A[1]\rightarrow A[i-1] A[1]A[i1]交换位置的次数,因为每交换一次位置,就消除一对逆序对,逆序对的次数等于 i − k i-k ik,( i i i A [ i ] A[i] A[i]原始位置, k k k A [ k ] A[k] A[k]插入位置)。

基于以上思路可以建议一棵空的顺序统计树,将 A [ i ] A[i] A[i]插入,然后查询 r a n k ( A [ i ] ) rank(A[i]) rank(A[i]),逆序对次数加 i − r a n k ( A [ i ] ) i-rank(A[i]) irank(A[i])

代码如下:

template<typename T>
int OS_reverseCount(vector<pNode<T>> &vec)
{
    int reverseCnt=0;
    OSTree<T> t;
    for(int i=1;i<=vec.size();++i)//遍历数组
    {
        OSTree_insert(t,vec[i-1]);//插入
        reverseCnt+=i-OS_rank(t,vec[i-1]);//计算插入位置减去原先位置
    }
    return reverseCnt;
}

另外也可以采用另一种方式,我们先将全部的关键字插入。然后在按插入顺序查询它在顺序统计树的位序,然后将它从树中删除。那么一组没有逆序对的数组,每次我们查询它的秩应该均是1,然后将它删除。否则,说明我们在一棵顺序统计树中先取出的树不是最小的,然后有更小的后面在取出,即存在逆序对。逆序对数等于每次查询的位序 r a n k ( A [ i ] ) − 1 rank(A[i])-1 rank(A[i])1的和。

代码如下:

template<typename T>
int OS_reverseCount2(vector<pNode<T>> &vec){
    OSTree<T> t;
    int reverseCnt=-vec.size();//相当于每个数都减1
    for(auto i:vec)//全部插入,插入顺序不重要
        OSTree_insert(t,i);
    for(int i=1;i<=vec.size();++i)//按顺序取出
    {
        reverseCnt+=OS_rank(t,vec[i-1]);//查询位置
        OSTree_delete(t,vec[i-1]);//删除
    }
    return reverseCnt;
}

第2个版本相比第一个版本耗费时间多一倍,需要删除和插入。两种方法均可以在 O ( n l g n ) O(nlgn) O(nlgn)时间内完成对逆序对的统计。

下面是我的顺序统计树的c++实现,顺序统计树基于红黑树实现,对于红黑树的介绍和代码实现可以看之前的文章数据结构红黑树和之前文章介绍的红黑树基本一致,只修改了的rotate函数和insert等需要调整属性 s i z e size size的函数。

#include<iostream>
#include<vector>
#include<queue>
#include<random>
#include<ctime>
using namespace std;
//定义颜色宏
enum COLOR{RED,BLACK};
//结点定义
template<typename T>
struct Node
{
    Node<T>* left;
    Node<T>* right;
    Node<T>* p;
    T key;
    int size;
    COLOR color;
    Node():color(BLACK),size(0){}
    Node(const T& k):color(BLACK),key(k),size(0){}
};
//定义指针
template<typename T>
using pNode=Node<T>*;
template<typename T>
struct OSTree
{   
    static pNode<T> nil;
    /**
     * Singleton Model
     * 采用local-static对象
     * 使模板参数相同的对象公用一个nil
     * 在main函数前被使用。
     * 具体参考 下面这篇博客
     * https://blog.csdn.net/qq_40512922/article/details/90589657#41_274
     */
    static pNode<T> getInstance(){
        static Node<T> one_instance;
        return &one_instance;
    }
    pNode<T> root;
    OSTree():root(nil){}
};
//初始化
template<typename T>
pNode<T> OSTree<T>::nil=OSTree<T>::getInstance();
/*
    Function Decleration
    ----------------------------------------
 */
template<typename T>//插入
void OSTree_insert(OSTree<T> &t,pNode<T> z);
template<typename T>//插入调整
void OSTree_insert_fixup(OSTree<T> &t,pNode<T> z);
template<typename T>//删除
void OSTree_delete(OSTree<T> &t,pNode<T> z);
template<typename T>//删除调整
void OSTree_delete_fixup(OSTree<T> &t,pNode<T> x);
template<typename T>//从from到to的size减1的简单路径size-1
void OSTree_delete_decreaseSize(pNode<T> from,pNode<T> to);
template<typename T>//O(1)空间复杂度迭代中序遍历
void inorder_travel_iterative(pNode<T> x);
template<typename T>//常规递归中序遍历
void inorder_travel_recursive(pNode<T> x);
template<typename T>//左旋
void left_rotate(OSTree<T> &t,pNode<T> z);
template<typename T>//右旋
void right_rotate(OSTree<T> &t,pNode<T> z);
template<typename T>//用v代替u的位置
void OSTree_transplant(OSTree<T> &t,pNode<T> u,pNode<T> v);
template<typename T>//最小值
pNode<T> tree_minimum(pNode<T> x);
template<typename T>//初始化vector
void getInitVec(vector<pNode<T>> &vec);
template<typename T>//释放内存
void freeVec(vector<pNode<T>> &vec);
template<typename T>//打印结点x
void print(const Node<T>*x);
template<typename T>//获取秩为i的结点
pNode<T> OS_select(pNode<T> x,int i);
template<typename T>//获取结点x的秩
int OS_rank(OSTree<T> &t,pNode<T> x);
template<typename T>
int OS_reverseCount(vector<pNode<T>> &vec);
template<typename T>
int OS_reverseCount2(vector<pNode<T>> &vec);
/*
    Function Definition
    ----------------------------------------
 */
template<typename T>
void print(const Node<T>*x)
{
    cout << "key = " << x->key << "size = " << x->size;
    if(x->color==BLACK)
        cout << " [BLACK]\n";
    else
        cout << " [RED]\n";
}
template<typename T>
void inorder_travel_recursive(pNode<T> x)
{
    if(x!=OSTree<T>::nil)
    {
        inorder_travel_recursive(x->left);
        print(x);
        inorder_travel_recursive(x->right);
    }
}
template<typename T>
void inorder_travel_iterative(pNode<T> x)
{
    if(x==OSTree<T>::nil)return;
    pNode<T> y=OSTree<T>::nil;
    while(true)
    {
        if(y!=x->left)
            while(x->left!=OSTree<T>::nil)
                x=x->left;
        print(x);
        if(x->right!=OSTree<T>::nil)
        {
            x=x->right;
            continue;
        }
        do{
            y=x;
            x=x->p;
            if(x==OSTree<T>::nil)
                return;
        }while(y==x->right);
    }
}
template<typename T>
void left_rotate(OSTree<T> &t,pNode<T> x) 
{
    pNode<T> y=x->right;
    x->right=y->left;
    if(y->left!=OSTree<T>::nil)
        y->left->p=x;
    y->p=x->p;
    if(x->p==OSTree<T>::nil)
        t.root=y;
    else if(x->p->left==x)
        x->p->left=y;
    else
        x->p->right=y;
    y->left=x;
    x->p=y;
    y->size = x->size;
    x->size = x->left->size+x->right->size+1;
}
template<typename T>
void right_rotate(OSTree<T> &t,pNode<T> x)
{
    pNode<T> y=x->left;
    x->left=y->right;
    if(y->right!=OSTree<T>::nil)
        y->right->p=x;
    y->p=x->p;
    if(x->p==OSTree<T>::nil)
        t.root=y;
    else if(x->p->left==x)
        x->p->left=y;
    else
        x->p->right=y;
    y->right=x;
    x->p=y;
    y->size = x->size;
    x->size = x->left->size + x->right->size+1;
}
template<typename T>
void OSTree_insert(OSTree<T> &t,pNode<T> z)
{
    pNode<T> y=OSTree<T>::nil;
    pNode<T> x=t.root;
    while(x!=OSTree<T>::nil)
    {
        y=x;
        ++y->size;// the y parent size add 1
        if(z->key<x->key)
            x=x->left;
        else
            x=x->right;
    }
    z->p=y;
    if(y==OSTree<T>::nil)
        t.root=z;
    else if(z->key<y->key)
        y->left=z;
    else
        y->right=z;
    z->left=z->right=OSTree<T>::nil;
    z->color=RED;
    z->size = 1;
    OSTree_insert_fixup(t,z);
}
template<typename T>
void OSTree_insert_fixup(OSTree<T> &t,pNode<T> z)
{
    while(z->p->color==RED)
    {
        if(z->p==z->p->p->left)
        {
            pNode<T> y=z->p->p->right;
            if(y->color==RED)
            {
                z->p->color=BLACK;  //case 1
                y->color=BLACK;
                z->p->p->color=RED;
                z=z->p->p;
            }
            else
            {
                if(z==z->p->right)
                {
                    z=z->p;         //case 2
                    left_rotate(t,z);
                }
                z->p->color=BLACK;  //case 3
                z->p->p->color=RED;
                right_rotate(t,z->p->p);
            }
        }//end-if
        else
        {
            pNode<T> y=z->p->p->left;
            if(y->color==RED)
            {
                z->p->color=BLACK;
                y->color=BLACK;
                z->p->p->color=RED;
                z=z->p->p;
            }
            else
            {
                if(z==z->p->left)
                {
                    z=z->p;
                    right_rotate(t,z);
                }
                z->p->color=BLACK;
                z->p->p->color=RED;
                left_rotate(t,z->p->p);
            }
        }//end-else
    }//end while
    t.root->color=BLACK;
}
template<typename T>
pNode<T> tree_minimum(pNode<T> x)
{
    while(x->left!=OSTree<T>::nil)
        x=x->left;
    return x;
}
template<typename T>
void OSTree_transplant(OSTree<T> &t,pNode<T> u,pNode<T> v)
{
    if(u->p==OSTree<T>::nil)
        t.root=v;
    else if(u==u->p->left)
        u->p->left=v;
    else
        u->p->right=v;
    v->p=u->p;
}
template<typename T>
void OSTree_delete_decreaseSize(pNode<T> from,pNode<T> to)
{
    while(from!=to)
    {
        --from->size;
        from=from->p;
    }
}
template<typename T>
void OSTree_delete(OSTree<T> &t,pNode<T> z)
{
    pNode<T> y=z;
    pNode<T> x;
    COLOR y_original_color=y->color;
    if(z->left==OSTree<T>::nil)
    {
        x=z->right;
        OSTree_delete_decreaseSize(z->p,OSTree<T>::nil);
        OSTree_transplant(t,z,z->right);
    }
    else if(z->right==OSTree<T>::nil)
    {
        x=z->left;
        OSTree_delete_decreaseSize(z->p,OSTree<T>::nil);
        OSTree_transplant(t,z,z->left);
    }
    else
    {
        y=tree_minimum(z->right);
        OSTree_delete_decreaseSize(y->p,OSTree<T>::nil);
        y->size=z->size;//y get the size of z
        y_original_color=y->color;
        x=y->right;
        if(y->p==z)
            x->p=y;
        else
        {
            OSTree_transplant(t,y,y->right);
            y->right=z->right;
            y->right->p=y;
        }
        OSTree_transplant(t,z,y);
        y->left=z->left;
        y->left->p=y;
        y->color=z->color;
    }
    z->size=0;//set size to 0 when del
    if(y_original_color==BLACK)
        OSTree_delete_fixup(t,x);
}
template<typename T>
void OSTree_delete_fixup(OSTree<T> &t,pNode<T> x)
{
    while(x!=t.root&&x->color==BLACK)
    {
        if(x==x->p->left)
        {
            pNode<T> w=x->p->right;//brother node
            if(w->color==RED)
            {
                w->color=BLACK;     //case 1
                x->p->color=RED;
                left_rotate(t,x->p);
                w=x->p->right;
            }
            if(w->left->color==BLACK&&w->right->color==BLACK)
            {
                w->color=RED;   //case 2
                x=x->p;
            }
            else
            {
                if(w->right->color==BLACK)
                {
                    w->left->color=BLACK;   //case 3
                    w->color=RED;
                    right_rotate(t,w);
                    w=x->p->right;
                }
                w->color=x->p->color;   //case 4
                x->p->color=BLACK;
                w->right->color=BLACK;
                left_rotate(t,x->p);
                x=t.root;
            }
        }//end-if
        else
        {
            pNode<T> w=x->p->left;
            if(w->color==RED)
            {
                w->color=BLACK;     //case 1
                x->p->color=RED;
                right_rotate(t,x->p);
                w=x->p->left;
            }
            if(w->left->color==BLACK&&w->right->color==BLACK)
            {
                w->color=RED;   //case 2
                x=x->p;
            }
            else
            {
                if(w->left->color==BLACK)
                {
                    w->right->color=BLACK;  //case 3
                    w->color=RED;
                    left_rotate(t,w);
                    w=x->p->left;
                }
                w->color=x->p->color;   //case 4
                x->p->color=BLACK;
                w->left->color=BLACK;
                right_rotate(t,x->p);
                x=t.root;
            }
        }//end-else
    }
    x->color=BLACK;
}
template<typename T>
pNode<T> OS_select(pNode<T> x,int i)
{
    //add the case of nil boundary
    if(x==OSTree<T>::nil)
        return x;
    int r=x->left->size+1;
    if(i==r)
        return x;
    else if(i<r)
        return OS_select(x->left,i);
    else
        return OS_select(x->right,i-r);
}
template<typename T>
int OS_rank(OSTree<T> &t,pNode<T> x)
{
    if(x==OSTree<T>::nil)
        return -1;
    int r=x->left->size+1;
    pNode<T> y=x;
    while(y!=t.root)
    {
        if(y==y->p->right)
            r+=y->p->left->size+1;
        y=y->p;
    }
    return r;
}
template<typename T>
int OS_reverseCount(vector<pNode<T>> &vec)
{
    int reverseCnt=0;
    OSTree<T> t;
    for(int i=1;i<=vec.size();++i)
    {
        OSTree_insert(t,vec[i-1]);
        reverseCnt+=i-OS_rank(t,vec[i-1]);
    }
    return reverseCnt;
}
template<typename T>
int OS_reverseCount2(vector<pNode<T>> &vec){
    OSTree<T> t;
    int reverseCnt=-vec.size();//相当于每个数都减1
    for(auto i:vec)
        OSTree_insert(t,i);
    for(int i=1;i<=vec.size();++i)
    {
        reverseCnt+=OS_rank(t,vec[i-1]);
        OSTree_delete(t,vec[i-1]);
    }
    return reverseCnt;
}

template<> void getInitVec(vector<pNode<int>> &vec)
{
    static default_random_engine e(time(nullptr));
    static uniform_int_distribution<int> d(0,50000);
    int key;
    for(auto &i:vec){
        i=new Node<int>();
        i->key=d(e);
    }
}
template<> void getInitVec(vector<pNode<double>> &vec)
{
    static default_random_engine e(time(nullptr));
    static uniform_real_distribution<double> d(0,50000);
    double key;
    for(auto &i:vec){
        i=new Node<double>();
        i->key=d(e);
    }
}
template<typename T>
void freeVec(vector<pNode<T>> &vec)
{
    for(auto i:vec)
    {
        delete i;
        i=nullptr;
    }
}

void OS_test_reverseCount()
{
    int cnt,y,k;
    cout << "Input the cnt:" << endl;
    cin>>cnt;
    vector<pNode<int>> vec(cnt);
    // getInitVec(vec);//随机获取数据
    cout << "Input the  key:";
    for(int i=0;i<vec.size();++i)
    {
        cin >> k;
        vec[i]=new Node<int>(k);
    }
    cout << OS_reverseCount(vec);
    // cout << OS_reverseCount2(vec);
    freeVec(vec);
}
int main()
{
    OS_test_reverseCount();
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,这是两个问题。让我分别回答。 --- 对于习题24.2-4,我们需要证明:对于有向图$G=(V,E)$,从源点$s$到任何其他点$v\in V$的最短路径上最多可以包含$|V|-1$条边。 我们可以使用反证法来证明这个结论。假设存在一条从$s$到$v$的最短路径包含了$|V|$条边。由于这是一条简单路径,所以它经过了$|V|$个顶点中的所有顶点。因此,这个路径形成了一个简单环。我们可以从这个简单环中删除任意一条边,得到一条从$s$到$v$的路径,路径长度比原来的最短路径长度更小,这与原来的最短路径的假设相矛盾。因此,假设不成立,结论得证。 --- 对于习题24.3-6,我们需要证明:如果负权重有向图$G$中不存在从源点$s$可达的负权重环,则Bellman-Ford算法能够正确地计算出从$s$到所有其他顶点的最短路径。 我们可以使用反证法来证明这个结论。假设存在一个从$s$到$v$的最短路径上存在一个负权重环。由于负权重环的存在,我们可以通过不断绕这个环走来无限制地减小路径长度,因此不存在从$s$到$v$的最短路径。但是,Bellman-Ford算法会在第$|V|$次松弛操作之前终止,并且在第$i$次松弛操作之后,算法会计算出从$s$到所有距离$s$不超过$i$的顶点的最短路径。因此,我们可以得出结论:如果负权重有向图$G$中不存在从源点$s$可达的负权重环,则Bellman-Ford算法能够正确地计算出从$s$到所有其他顶点的最短路径。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值