演算法導論 14 2 Josephus排列

2021-06-14 16:14:45 字數 4318 閱讀 5684

分類: 演算法導論

2012-08-28 11:00

445人閱讀收藏 

舉報題目:

josephus問題的定義如下:假設n個人排成環形,且有以正整數m<=n。從某個制定的人開始,沿環報數,每遇到第m個人就讓其出列,且報數進行下去。這個過程一直進行到所有人都出列為止。每個人出列的次序定義了整數1,2,...,n的(n, m)-josephus排列。例如,(7,3)-josephus排列為<3,6,2,7,5,1,4>。

a)假設m為整數。請描述乙個o(n)時間的演算法,使之對給定的整數n,輸出(n, m)-josephus排列。

b)假設m不是個常數。請描述乙個o(nlgn)時間的演算法,使給定的整數n和m,輸出(n, m)-josephus排列。

思考:

利用14.1中的動態順序統計,假設剛剛刪除的是剩餘點中的第start個點(初始時為0),此時還剩下t個點,那麼下乙個要刪除的是剩餘點的第(start+m-1)%t個點

步驟1:基礎資料結構

紅黑樹步驟2:附加資訊

size[x]:以x為根的子樹的(內部)結點數(包括x本身),即子樹的大小。size[nil[t]]=0

步驟3:對資訊的維護

size[x] = size[left[x]] + size[right[x]] + 1

插入操作:從插入結點到根結點都要更新o(lgn)

旋轉操作:只需要更新旋轉軸上的兩個點o(1)

刪除操作:從刪除結點的父結點開始到根結點都要更新o(lgn)

**:

[cpp]view plain

copy

#include 

using

namespace

std;  

#define black 0

#define red 1

//紅黑樹結點結構

struct

node  

};  

//順序統計量樹結構

struct

os_tree  

;  };  

//對附加資訊的維護

void

maintaining(node *x)  

}  //左旋,令y = x->right, 左旋是以x和y之間的鏈為支軸進行旋轉

//涉及到的結點包括:x,y,y->left,令node=,具體變化如下:

//x=變為

//y=變為

//y->left=變為

void

left_rotate(os_tree *t, node *x)  

//右旋,令y = x->left, 左旋是以x和y之間的鏈為支軸進行旋轉

//旋轉過程與上文類似

void

right_rotate(os_tree *t, node *x)  

//紅黑樹調整

void

os_tree_insert_fixup(os_tree *t, node *z)  

else

//第三種情況:z的叔叔是黑色的,且z是左孩子

//交換parent[z]和parent[parent[z]]的顏色,並右旋

z->parent->color = black;  

z->parent->parent->color = red;  

right_rotate(t, z->parent->parent);  

}  }  

//parent[z]是右孩子時,有三種情況,與上面類似

else

if(z->parent == z->parent->parent->right)  

else

z->parent->color = black;  

z->parent->parent->color = red;  

left_rotate(t, z->parent->parent);  

}  }  

}  //根結點置為黑色

t->root->color = black;  

}  //插入乙個結點

void

os_tree_insert(os_tree *t, node *z)  

z->parent = y;  

if(y == t->nil)  

t->root = z;  

else

if(z->key < y->key)  

y->left = z;  

else

y->right = z;  

z->left = t->nil;  

z->right = t->nil;  

//將新插入的結點轉為紅色

z->color = red;  

//從新插入的結點開始,向上調整

os_tree_insert_fixup(t, z);  

maintaining(z);  

}  //對樹進行調整,x指向乙個紅黑結點,調整的過程是將額外的黑色沿樹上移

void

os_tree_delete_fixup(os_tree *t, node *x)  

//第二情況:w為黑色,w的兩個孩子也都是黑色

if(w->left->color == black && w->right->color == black)  

//第三種情況,w是黑色的,w->left是紅色的,w->right是黑色的

else

//第四種情況:w是黑色的,w->left是黑色的,w->right是紅色的

//修改w和parent[x]的顏色

w->color =x->parent->color;  

x->parent->color = black;  

w->right->color = black;  

//對parent[x]進行一次左旋

left_rotate(t, x->parent);  

//此時調整已經結束,將x置為根結點是為了結束迴圈

x = t->root;  

}  }  

//若x是其父的左結點(右結點的情況相對應)

else

if(x == x->parent->right)  

//第二情況:w為黑色,w的兩個孩子也都是黑色

if(w->right->color == black && w->left->color == black)  

//第三種情況,w是黑色的,w->right是紅色的,w->left是黑色的

else

//第四種情況:w是黑色的,w->right是黑色的,w->left是紅色的

//修改w和parent[x]的顏色

w->color =x->parent->color;  

x->parent->color = black;  

w->left->color = black;  

//對parent[x]進行一次左旋

right_rotate(t, x->parent);  

//此時調整已經結束,將x置為根結點是為了結束迴圈

x = t->root;  

}  }  

}  //吸收了額外的黑色

x->color = black;  

}  //找最小值   

node *os_tree_minimum(os_tree *t, node *x)    

//查詢中序遍歷下x結點的後繼,後繼是大於key[x]的最小的結點   

node *os_tree_successor(os_tree *t, node *x)    

return

y;    

}    

//遞迴地查詢二叉查詢樹   

node *os_tree_search(node *x, int

k)    

//紅黑樹的刪除

node *os_tree_delete(os_tree *t, node *z)  

//如果被刪除的結點是黑色的,則需要調整

if(y->color == black)  

os_tree_delete_fixup(t, x);  

return

y;  

}  //查詢以x為根結點的樹中第i大的結點  

node *os_tree_select(node *x, int

i)    

intmain()  

intt = n, start = 0;  

//還有剩餘結點

while

(t)  

cout<}  

return

0;  

}  

演算法導論14 2

本小節介紹了擴充套件資料結構的抽象過程,同時證明了乙個定理 選擇一種基礎資料結構 確定基礎資料結構中要維護的附加資訊 檢驗基礎資料結構上的基本修改操作能否維護附加資訊 設計一些新的操作來應用附加資訊 設 f 是 n 個節點的紅黑樹 t 擴張的屬性,且假設對任一節點 x f 的值僅依賴於節點 x,x....

演算法導論14 2如何擴張資料結構 練習總結

14.2 1 通過為結點增加指標的方式,試說明如何在擴張的順序統計樹上,支援每一動態集合查詢操作 minimum maximum successor 和 predecessor 在最壞時間 o 1 內完成。順序統計樹上的其他操作的漸進性能不受影響。answer minimum 用乙個指標指向樹中最小...

趣味演算法(一)Josephus問題

josephus問題求解 設有n個人圍坐乙個圓桌周圍,現從第s人開始報數,數到第m的人出列,然後從出列的下乙個重新開始報數,數列的第m個人又出列 如此重複,直 到所有的人全部出列為止。對任意給定的n s m,求按出列次序得到的n個 人員的順序表。分析 對於n個人,每一次出列乙個人,餘下的n 1個人仍...