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[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 − k i-k i−k,( 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]) 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,然后将它删除。否则,说明我们在一棵顺序统计树中先取出的树不是最小的,然后有更小的后面在取出,即存在逆序对。逆序对数等于每次查询的位序 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;
}