分類: 演算法導論
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個人仍...