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

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

这里我们将采用书中的顺序统计树(order-statistic tree)来解决。其实本质上和线段树类似,都是采用一种支持O(lgn)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[i−1]之中大于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[i−1]交换位置的次数,因为每交换一次位置,就消除一对逆序对,逆序对的次数等于i−ki-ki−k,(iii为A[i]A[i]A[i]原始位置,kkk为A[k]A[k]A[k]插入位置)。

基于以上思路可以建议一棵空的顺序统计树,将A[i]A[i]A[i]插入,然后查询rank(A[i])rank(A[i])rank(A[i]),逆序对次数加i−rank(A[i])i-rank(A[i])i−rank(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,然后将它删除。否则,说明我们在一棵顺序统计树中先取出的树不是最小的,然后有更小的后面在取出,即存在逆序对。逆序对数等于每次查询的位序rank(A[i])−1rank(A[i])-1rank(A[i])−1的和。

代码如下:

template<typename T>
int OS_reverseCount2(vector<pNode<T>> &vec){OSTree<T> t;int reverseCnt=-vec.size();//相当于每个数都减1for(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(nlgn)O(nlgn)O(nlgn)时间内完成对逆序对的统计。

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

#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";elsecout << " [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;elsex->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;elsex->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 1if(z->key<x->key)x=x->left;elsex=x->right;}z->p=y;if(y==OSTree<T>::nil)t.root=z;else if(z->key<y->key)y->left=z;elsey->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 1y->color=BLACK;z->p->p->color=RED;z=z->p->p;}else{if(z==z->p->right){z=z->p;         //case 2left_rotate(t,z);}z->p->color=BLACK;  //case 3z->p->p->color=RED;right_rotate(t,z->p->p);}}//end-ifelse{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 whilet.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;elseu->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 zy_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 delif(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 nodeif(w->color==RED){w->color=BLACK;     //case 1x->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 2x=x->p;}else{if(w->right->color==BLACK){w->left->color=BLACK;   //case 3w->color=RED;right_rotate(t,w);w=x->p->right;}w->color=x->p->color;   //case 4x->p->color=BLACK;w->right->color=BLACK;left_rotate(t,x->p);x=t.root;}}//end-ifelse{pNode<T> w=x->p->left;if(w->color==RED){w->color=BLACK;     //case 1x->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 2x=x->p;}else{if(w->left->color==BLACK){w->right->color=BLACK;  //case 3w->color=RED;left_rotate(t,w);w=x->p->left;}w->color=x->p->color;   //case 4x->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 boundaryif(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);elsereturn 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();//相当于每个数都减1for(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;
}

算法导论 练习14.1-7相关推荐

  1. 二叉树的遍历(算法导论第三版12.1-4)(包含先序遍历,后序遍历和中序遍历)

    二叉树的遍历(算法导论第三版12.1-4) 1⃣️先序遍历 template<typename T> void preorder_tree_wald(BinaryTreeNode<T ...

  2. 算法导论第三版第十一章11.1-4

    算法导论第三版第十一章11.1-4 我们希望在一个非常大的数组上,通过利用直接寻址的方式来实现一个字典.开始时,该数组中可能包含一些无用信息,但要堆整个数组进行初始化时不太实际的,因为该数组的规模太大 ...

  3. 算法导论第16章练习题 16.1-4

    16.1-4 假设有一组活动,我们需要将它们安排到一些教室,任意活动都可以在任意教室进行.我们希望使用最少的教室来完成活动.设计一个高效的贪心算法,求每个活动应该在哪个教室来进行. (这个问题也被称为 ...

  4. 算法导论Java实现-构建MaxHeap

    package lhz.algorithm.chapter.six; /** * "构建堆",<算法导论>6.3章节 Building a heap * 利用之前实现的 ...

  5. 《算法导论》读书笔记(七)

    <算法导论>读书笔记之第16章 贪心算法-活动选择问题 前言:贪心算法也是用来解决最优化问题,将一个问题分成子问题,在现在子问题最优解的时,选择当前看起来是最优的解,期望通过所做的局部最优 ...

  6. Python语言程序设计之urllib.request抓取页面,网易公开课之《麻省理工学院公开课:算法导论》

    Python语言用urllib.request模块抓取页面非常简单,再将抓取的页面内容用re模块解析,找出自己想要的东西.下面就就此方法来抓取网易公开课之<麻省理工学院公开课:算法导论>, ...

  7. 《算法导论》中动态规划求解钢条切割问题

    动态规划算法概述 动态规划(dynamic programming)1是一种与分治方法很像的方法,都是通过组合子问题的解来求解原问题.不同之处在于,动态规划用于子问题重叠的情况,比如我们学过的斐波那契 ...

  8. 《算法导论》学习总结 — 21.第16章 贪心算法(1) 基础入门1

    建议先看看前言:http://www.wutianqi.com/?p=2298 连载总目录:http://www.wutianqi.com/?p=2403 说到贪心算法,避免不了于DP对比,所以前面的 ...

  9. 给定一个n节点二叉树,写出一个O(n)时间的非递归的过程,将该树每个结点的关键字输出(算法导论第三版第十章10.4-5)

    给定一个n节点二叉树,写出一个O(n)时间的非递归的过程,将该树每个结点的关键字输出.要求除该树本树的存储空间外只能使用固定量的额外存储空间,且过程中不得修改该树,即使是暂时的修改也不允许. (算法导 ...

最新文章

  1. 学生课程表管理系统——stage 1
  2. bitand( ) 函数用法
  3. 高速掌握Lua 5.3 —— 字符串库 (2)
  4. [密码学] 公钥密码基础与RSA
  5. [hypervisor]-ARMV8的hypervisor技术介绍–InProgress
  6. 名为 cursor_jinserted 的游标不存在_生鲜电商存在的问题及对策解析:未来生鲜电商如何发展?...
  7. 惊了,掌握了这个炼丹技巧的我开始突飞猛进
  8. 带你学习ES5中新增的方法
  9. PMI、砺志咨询活动:项目经理软技能征文大赛—15个PDU、免费软技能培训
  10. Git安装配置与GitHub注册及简单使用
  11. laravel手册链接
  12. ZOJ 4093 浙大校赛D题 Robot Cleaner II(思维+构造题)
  13. flv转mp4,电脑视频flv怎么批量转mp4格式
  14. 嵌入式linux下控制电机运动
  15. FeignClient调用 Cannot deserialize instance of `java.lang.Boolean` out of START_OBJECT token to
  16. stm32cubeide烧写程序_STM32 Cube IDE 下实现 IAP —— (1) 程序跳转
  17. 【shaw学习笔记day1】Python21天+人工智能预科学习日记
  18. 专题05-python操作微信(wxpy)
  19. 图片压缩工具riottinypng
  20. 原生ajax和Jquery的ajax

热门文章

  1. 关于RDLC使用导出PDF文件时,中文乱码解决方案
  2. 【JPA 级联保存/级联删除】@OneToMany (双向) 一对多【转】
  3. hive高级数据类型
  4. oracle之三闪回flashback
  5. node 无脑生成小程序二维码图
  6. 可并堆试水--BZOJ1367: [Baltic2004]sequence
  7. 10分钟学习简略五子棋 源码+注释教学
  8. 【数据库系统设计】关系数据库标准语言SQL(1)
  9. 《恋上数据结构第1季》集合 ListSet、TreeSet、HashSet
  10. django进阶04部署上线(nginx,uwsgi,supervisor)