平衡演算法
A. 雙足機器人有哪些常見的平衡演算法
在最開始的雙足機器人使用的平衡控制策略是「靜態步行」(static walking)
這種策略的特點是:機器人步行的過程中,重心(COG,Center of Gravity)的投影始終位於多邊形支撐區域(support region)內,
這種控制策略的好處在於:在整個的行進過程中,機器人可以在行走動作中停止而不摔倒,但代價是行動速度非常遲緩(每一步需要花費10秒甚至更長)(因為需要保持重心的投影始終位於支撐區域,否則將不穩定),因為靜態步行和人類的期望相差甚遠,
於是人類開發出來了另一種步行平衡策略:「動態步行」(dynamic walking)。
在動態步行中機器人的行動速度被提升至了每步不超過1秒。但是弊端也是顯而易見的,機器人難以在運動的狀態下立即停頓(慣性的作用),從而使得機器人在狀態轉換的過程中變得不穩定。為了解決慣性帶來的影響,零力矩點(ZMP,zero moment point)被引入到了這一控制策略中。在單腳支撐相中,ZMP=COG。引入ZMP的好處在於,如果ZMP嚴格的存在於機器人的支撐區域中,機器人絕對不會摔倒。
Xzmp代表正向ZMP,Xmc代表質量中心的前進位移,l是倒立擺的長度,g是重力加速度。
由於復雜地形的雙足平衡無法由單一的控制器實現,所以多個控制器的切換策略被用於解決平衡問題。在這一個策略中,機器人的行走被設定為一個周期(cycle)每一個周期被分成了不同的行走階段(stage)
B. 求演算法:三相平衡度如何算!
a44
,
b22
,
c11
有超過嗎如何算?44,22,11是電流嗎?如果是,則朋友小學沒學好!44-11/44X100%=75%
不平衡達75%,與15%差了5倍!
C. 生產線平衡的計算方法
要衡量工藝總平衡狀態的好壞,我們必須設定一個定量值來表示,即生產線平衡率或平衡損失率,以百分率表示。 首先,要明確一點,雖然各工序的工序時間長短不同,但如前所述,決定生產線的作業周期的工序時間只有一個,即最長工序時間--瓶頸工序時間。同時需要區分瓶頸時間與節拍時間,所謂的節拍時間TAKT TIME 是按照客戶要求設計的,他的計算方法是等於工作時間*3600sec/需求產量
1、生產線的平衡計算公式
平衡率=(各工序時間總和/(工站數*瓶頸工序時間))*100%=(∑ti/(工站數*CT))*100%
2、生產線的平衡損失率計算公式
平衡損失率=1-(各工序時間總和/(工站數*Takt 時間)) ;
可以參考附圖
D. 有沒有人懂加全平衡演算法求公式
比如數學、物理、化學是最強主科,每科權值是3。語文英語是次之主科,每科權值是2。歷史地理是副科,每科權值是1。小紅各科分數:數學60、物理50、化學50、語文70、英語80、歷史90、地理100。小紅加權平均分值=(60*3+50*3+50*3+70*2+80*2+90*1+100*1)/(3+3+3+2+2+1+1)=970/15=64.67分,權值越高,對最後結果影響越大!手機手打,望採納
E. B-tree的平衡演算法
/* btrees.h */
/*
* 平衡多路樹的一種重要方案。
* 在 1970 年由 R. Bayer 和 E. McCreight 發明。
*/
#define M 1
/* B 樹的階,即非根節點中鍵的最小數目。
* 有些人把階定義為非根節點中子樹的最大數目。
*/
typedef int typekey;
typedef struct btnode { /* B-Tree 節點 */
int d; /* 節點中鍵的數目 */
typekey k[2*M]; /* 鍵 */
char *v[2*M]; /* 值 */
struct btnode *p[2*M+1]; /* 指向子樹的指針 */
} node, *btree;
/*
* 每個鍵的左子樹中的所有的鍵都小於這個鍵,
* 每個鍵的右子樹中的所有的鍵都大於等於這個鍵。
* 葉子節點中的每個鍵都沒有子樹。
*/
/* 當 M 等於 1 時也稱為 2-3 樹
* +----+----+
* | k0 | k1 |
* +-+----+----+---
* | p0 | p1 | p2 |
* +----+----+----+
*/
extern int btree_disp; /* 查找時找到的鍵在節點中的位置 */
extern char * InsValue; /* 與要插的鍵相對應的值 */
extern btree search(typekey, btree);
extern btree insert(typekey,btree);
extern btree delete(typekey,btree);
extern int height(btree);
extern int count(btree);
extern double payload(btree);
extern btree deltree(btree);
/* end of btrees.h */
/*******************************************************/
/* btrees.c */
#include <stdlib.h>
#include <stdio.h>
#include btrees.h
btree search(typekey, btree);
btree insert(typekey,btree);
btree delete(typekey,btree);
int height(btree);
int count(btree);
double payload(btree);
btree deltree(btree);
static void InternalInsert(typekey, btree);
static void InsInNode(btree, int);
static void SplitNode(btree, int);
static btree NewRoot(btree);
static void InternalDelete(typekey, btree);
static void JoinNode(btree, int);
static void MoveLeftNode(btree t, int);
static void MoveRightNode(btree t, int);
static void DelFromNode(btree t, int);
static btree FreeRoot(btree);
static btree delall(btree);
static void Error(int,typekey);
int btree_disp; /* 查找時找到的鍵在節點中的位置 */
char * InsValue = NULL; /* 與要插的鍵相對應的值 */
static int flag; /* 節點增減標志 */
static int btree_level = 0; /* 多路樹的高度 */
static int btree_count = 0; /* 多路樹的鍵總數 */
static int node_sum = 0; /* 多路樹的節點總數 */
static int level; /* 當前訪問的節點所處的高度 */
static btree NewTree; /* 在節點分割的時候指向新建的節點 */
static typekey InsKey; /* 要插入的鍵 */
btree search(typekey key, btree t)
{
int i,j,m;
level=btree_level-1;
while (level >= 0){
for(i=0, j=t->d-1; i<j; m=(j+i)/2, (key > t->k[m])?(i=m+1):(j=m));
if (key == t->k [ i ]){
btree_disp = i;
return t;
}
if (key > t->k [ i ]) /* i == t->d-1 時有可能出現 */
i++;
t = t->p[ i ];
level--;
}
return NULL;
}
btree insert(typekey key, btree t)
{
level=btree_level;
InternalInsert(key, t);
if (flag == 1) /* 根節點滿之後,它被分割成兩個半滿節點 */
t=NewRoot(t); /* 樹的高度增加 */
return t;
}
void InternalInsert(typekey key, btree t)
{
int i,j,m;
level--;
if (level < 0){ /* 到達了樹的底部: 指出要做的插入 */
NewTree = NULL; /* 這個鍵沒有對應的子樹 */
InsKey = key; /* 導致底層的葉子節點增加鍵值+空子樹對 */
btree_count++;
flag = 1; /* 指示上層節點把返回的鍵插入其中 */
return;
}
for(i=0, j=t->d-1; i<j; m=(j+i)/2, (key > t->k[m])?(i=m+1):(j=m));
if (key == t->k[ i ]) {
Error(1,key); /* 鍵已經在樹中 */
flag = 0;
return;
}
if (key > t->k[ i ]) /* i == t->d-1 時有可能出現 */
i++;
InternalInsert(key, t->p[ i ]);
if (flag == 0)
return;
/* 有新鍵要插入到當前節點中 */
if (t->d < 2*M) {/* 當前節點未滿 */
InsInNode(t, i); /* 把鍵值+子樹對插入當前節點中 */
flag = 0; /* 指示上層節點沒有需要插入的鍵值+子樹,插入過程結束 */
}
else /* 當前節點已滿,則分割這個頁面並把鍵值+子樹對插入當前節點中 */
SplitNode(t, i); /* 繼續指示上層節點把返回的鍵值+子樹插入其中 */
}
/*
* 把一個鍵和對應的右子樹插入一個節點中
*/
void InsInNode(btree t, int d)
{
int i;
/* 把所有大於要插入的鍵值的鍵和對應的右子樹右移 */
for(i = t->d; i > d; i--){
t->k[ i ] = t->k[i-1];
t->v[ i ] = t->v[i-1];
t->p[i+1] = t->p[ i ];
}
/* 插入鍵和右子樹 */
t->k[ i ] = InsKey;
t->p[i+1] = NewTree;
t->v[ i ] = InsValue;
t->d++;
}
/*
* 前件是要插入一個鍵和對應的右子樹,並且本節點已經滿
* 導致分割這個節點,插入鍵和對應的右子樹,
* 並向上層返回一個要插入鍵和對應的右子樹
*/
void SplitNode(btree t, int d)
{
int i,j;
btree temp;
typekey temp_k;
char *temp_v;
/* 建立新節點 */
temp = (btree)malloc(sizeof(node));
/*
* +---+--------+-----+-----+--------+-----+
* | 0 | ...... | M | M+1 | ...... |2*M-1|
* +---+--------+-----+-----+--------+-----+
* |<- M+1 ->|<- M-1 ->|
*/
if (d > M) { /* 要插入當前節點的右半部分 */
/* 把從 2*M-1 到 M+1 的 M-1 個鍵值+子樹對轉移到新節點中,
* 並且為要插入的鍵值+子樹空出位置 */
for(i=2*M-1,j=M-1; i>=d; i--,j--) {
temp->k[j] = t->k[ i ];
temp->v[j] = t->v[ i ];
temp->p[j+1] = t->p[i+1];
}
for(i=d-1,j=d-M-2; j>=0; i--,j--) {
temp->k[j] = t->k[ i ];
temp->v[j] = t->v[ i ];
temp->p[j+1] = t->p[i+1];
}
/* 把節點的最右子樹轉移成新節點的最左子樹 */
temp->p[0] = t->p[M+1];
/* 在新節點中插入鍵和右子樹 */
temp->k[d-M-1] = InsKey;
temp->p[d-M] = NewTree;
temp->v[d-M-1] = InsValue;
/* 設置要插入上層節點的鍵和值 */
InsKey = t->k[M];
InsValue = t->v[M];
}
else { /* d <= M */
/* 把從 2*M-1 到 M 的 M 個鍵值+子樹對轉移到新節點中 */
for(i=2*M-1,j=M-1; j>=0; i--,j--) {
temp->k[j] = t->k[ i ];
temp->v[j] = t->v[ i ];
temp->p[j+1] = t->p[i+1];
}
if (d == M) /* 要插入當前節點的正中間 */
/* 把要插入的子樹作為新節點的最左子樹 */
temp->p[0] = NewTree;
/* 直接把要插入的鍵和值返回給上層節點 */
else { /* (d<M) 要插入當前節點的左半部分 */
/* 把節點當前的最右子樹轉移成新節點的最左子樹 */
temp->p[0] = t->p[M];
/* 保存要插入上層節點的鍵和值 */
temp_k = t->k[M-1];
temp_v = t->v[M-1];
/* 把所有大於要插入的鍵值的鍵和對應的右子樹右移 */
for(i=M-1; i>d; i--) {
t->k[ i ] = t->k[i-1];
t->v[ i ] = t->v[i-1];
t->p[i+1] = t->p[ i ];
}
/* 在節點中插入鍵和右子樹 */
t->k[d] = InsKey;
t->p[d+1] = NewTree;
t->v[d] = InsValue;
/* 設置要插入上層節點的鍵和值 */
InsKey = temp_k;
InsValue = temp_v;
}
}
t->d =M;
temp->d = M;
NewTree = temp;
node_sum++;
}
btree delete(typekey key, btree t)
{
level=btree_level;
InternalDelete(key, t);
if (t->d == 0)
/* 根節點的子節點合並導致根節點鍵的數目隨之減少,
* 當根節點中沒有鍵的時候,只有它的最左子樹可能非空 */
t=FreeRoot(t);
return t;
}
void InternalDelete(typekey key, btree t)
{
int i,j,m;
btree l,r;
int lvl;
level--;
if (level < 0) {
Error(0,key); /* 在整個樹中未找到要刪除的鍵 */
flag = 0;
return;
}
for(i=0, j=t->d-1; i<j; m=(j+i)/2, (key > t->k[m])?(i=m+1):(j=m));
if (key == t->k[ i ]) { /* 找到要刪除的鍵 */
if (t->v[ i ] != NULL)
free(t->v[ i ]); /* 釋放這個節點包含的值 */
if (level == 0) { /* 有子樹為空則這個鍵位於葉子節點 */
DelFromNode(t,i);
btree_count--;
flag = 1;
/* 指示上層節點本子樹的鍵數量減少 */
return;
} else { /* 這個鍵位於非葉節點 */
lvl = level-1;
/* 找到前驅節點 */
r = t->p[ i ];
while (lvl > 0) {
r = r->p[r->d];
lvl--;
}
t->k[ i ]=r->k[r->d-1];
t->v[ i ]=r->v[r->d-1];
r->v[r->d-1]=NULL;
key = r->k[r->d-1];
}
}
else if (key > t->k[ i ]) /* i == t->d-1 時有可能出現 */
i++;
InternalDelete(key,t->p[ i ]);
/* 調整平衡 */
if (flag == 0)
return;
if (t->p[ i ]->d < M) {
if (i == t->d) /* 在最右子樹中發生了刪除 */
i--; /* 調整最右鍵的左右子樹平衡 */
l = t->p [ i ];
r = t->p[i+1];
if (r->d > M)
MoveLeftNode(t,i);
else if(l->d > M)
MoveRightNode(t,i);
else {
JoinNode(t,i);
/* 繼續指示上層節點本子樹的鍵數量減少 */
return;
}
flag = 0;
/* 指示上層節點本子樹的鍵數量沒有減少,刪除過程結束 */
}
}
/*
* 合並一個節點的某個鍵對應的兩個子樹
*/
void JoinNode(btree t, int d)
{
btree l,r;
int i,j;
l = t->p[d];
r = t->p[d+1];
/* 把這個鍵下移到它的左子樹 */
l->k[l->d] = t->k[d];
l->v[l->d] = t->v[d];
/* 把右子樹中的所有鍵值和子樹轉移到左子樹 */
for (j=r->d-1,i=l->d+r->d; j >= 0 ; j--,i--) {
l->k[ i ] = r->k[j];
l->v[ i ] = r->v[j];
l->p[ i ] = r->p[j];
}
l->p[l->d+r->d+1] = r->p[r->d];
l->d += r->d+1;
/* 釋放右子樹的節點 */
free(r);
/* 把這個鍵右邊的鍵和對應的右子樹左移 */
for (i=d; i < t->d-1; i++) {
t->k[ i ] = t->k[i+1];
t->v[ i ] = t->v[i+1];
t->p[i+1] = t->p[i+2];
}
t->d--;
node_sum--;
}
/*
* 從一個鍵的右子樹向左子樹轉移一些鍵,使兩個子樹平衡
*/
void MoveLeftNode(btree t, int d)
{
btree l,r;
int m; /* 應轉移的鍵的數目 */
int i,j;
l = t->p[d];
r = t->p[d+1];
m = (r->d - l->d)/2;
/* 把這個鍵下移到它的左子樹 */
l->k[l->d] = t->k[d];
l->v[l->d] = t->v[d];
/* 把右子樹的最左子樹轉移成左子樹的最右子樹
* 從右子樹向左子樹移動 m-1 個鍵+子樹對 */
for (j=m-2,i=l->d+m-1; j >= 0; j--,i--) {
l->k[ i ] = r->k[j];
l->v[ i ] = r->v[j];
l->p[ i ] = r->p[j];
}
l->p[l->d+m] = r->p[m-1];
/* 把右子樹的最左鍵提升到這個鍵的位置上 */
t->k[d] = r->k[m-1];
t->v[d] = r->v[m-1];
/* 把右子樹中的所有鍵值和子樹左移 m 個位置 */
r->p[0] = r->p[m];
for (i=0; i<r->d-m; i++) {
r->k[ i ] = r->k[i+m];
r->v[ i ] = r->v[i+m];
r->p[ i ] = r->p[i+m];
}
r->p[r->d-m] = r->p[r->d];
l->d+=m;
r->d-=m;
}
/*
* 從一個鍵的左子樹向右子樹轉移一些鍵,使兩個子樹平衡
*/
void MoveRightNode(btree t, int d)
{
btree l,r;
int m; /* 應轉移的鍵的數目 */
int i,j;
l = t->p[d];
r = t->p[d+1];
m = (l->d - r->d)/2;
/* 把右子樹中的所有鍵值和子樹右移 m 個位置 */
r->p[r->d+m]=r->p[r->d];
for (i=r->d-1; i>=0; i--) {
r->k[i+m] = r->k[ i ];
r->v[i+m] = r->v[ i ];
r->p[i+m] = r->p[ i ];
}
/* 把這個鍵下移到它的右子樹 */
r->k[m-1] = t->k[d];
r->v[m-1] = t->v[d];
/* 把左子樹的最右子樹轉移成右子樹的最左子樹 */
r->p[m-1] = l->p[l->d];
/* 從左子樹向右子樹移動 m-1 個鍵+子樹對 */
for (i=l->d-1,j=m-2; j>=0; j--,i--) {
r->k[j] = l->k[ i ];
r->v[j] = l->v[ i ];
r->p[j] = l->p[ i ];
}
/* 把左子樹的最右鍵提升到這個鍵的位置上 */
t->k[d] = l->k[ i ];
t->v[d] = l->v[ i ];
l->d-=m;
r->d+=m;
}
/*
* 把一個鍵和對應的右子樹從一個節點中刪除
*/
void DelFromNode(btree t, int d)
{
int i;
/* 把所有大於要刪除的鍵值的鍵左移 */
for(i=d; i < t->d-1; i++) {
t->k[ i ] = t->k[i+1];
t->v[ i ] = t->v[i+1];
}
t->d--;
}
/*
* 建立有兩個子樹和一個鍵的根節點
*/
btree NewRoot(btree t)
{
btree temp;
temp = (btree)malloc(sizeof(node));
temp->d = 1;
temp->p[0] = t;
temp->p[1] = NewTree;
temp->k[0] = InsKey;
temp->v[0] = InsValue;
btree_level++;
node_sum++;
return(temp);
}
/*
* 釋放根節點,並返回它的最左子樹
*/
btree FreeRoot(btree t)
{
btree temp;
temp = t->p[0];
free(t);
btree_level--;
node_sum--;
return temp;
}
void Error(int f,typekey key)
{
if (f)
printf(Btrees error: Insert %d!
,key);
else
printf(Btrees error: delete %d!
,key);
}
int height(btree t)
{
return btree_level;
}
int count(btree t)
{
return btree_count;
}
double payload(btree t)
{
if (node_sum==0)
return 1;
return (double)btree_count/(node_sum*(2*M));
}
btree deltree (btree t)
{
level=btree_level;
btree_level = 0;
return delall(t);
}
btree delall(btree t)
{
int i;
level--;
if (level >= 0) {
for (i=0; i < t->d; i++)
if (t->v[ i ] != NULL)
free(t->v[ i ]);
if (level > 0)
for (i=0; i<= t->d ; i++)
t->p[ i ]=delall(t->p[ i ]);
free(t);
}
return NULL;
}
/* end of btrees.c */
F. 平衡二叉樹演算法
多值結點平衡二叉樹的結構及演算法研究
1引言
傳統的AV1.樹是一種應用較為廣泛的數據結構,適合」幾組織在內存中的較小索引.它的
每個結l從上存儲有一個關鍵字、一個平衡因子和兩個指針項,山」幾它是一棵接近」幾理想狀態的
平衡二叉樹,所以AV1.樹具有很高的查詢效率.但正如任何事物都具有兩而性一樣,AV1.樹同
樣存在比較嚴重的缺l從,一是存儲效率比較低:真正有用的關鍵字在結l從上所,片的空間比例較
小,而作為輔助信息的平衡因子和指針卻,片據較大的空間;二是額外運算量比較大:當有結l從
被插入或刪除而導致AV1.樹不平衡時,AV1.樹就需要進行調整而保持它的平衡性,山」幾每個
結l從上只有一個關鍵字,所以任何一次的數據插入或刪除都有可能導致AV1.樹的平衡調整,
這種頻繁的調整運算將大大降低AV1.樹的存取效率.為解決以上問題,結合T3樹每個結l從可
以存儲多個關鍵字項的優l側}l,木文提出了多值結l從平衡二叉樹(簡稱MAV1.樹),它的主要特
點在」幾每個MAV1.樹的結l從都存儲有多個關鍵字項,而其它信息仍與AV1.樹一樣,即一個平
衡因子和兩個指針項.
2 MAV1.樹結構描述
MAV1.樹仍舊是一種平衡二叉樹,它的整體樹型結構和演算法也是建立在傳統的平衡二叉
樹基礎之上的.MAV1.樹的特徵在」幾它的每個結l從都可以存儲多個關鍵字(較理想的取值大約
在20} 50個之間).用C++語言描述的MAV1.樹結l從結構如卜:
struct NodeStruct
int IJ1emsOnNode;
int bf:
struct NodPStruct*lch;ld:
//一結點中項的數目
//平衡因子
//夕.子
struct NodeStruct * rchild:
}lemType }lemsi Max}lem} ;//結點中的項數組
Node T:
在這種結構中.ElemsOnNode反映的是「當前狀態卜」該結l從中關鍵字項的個數.當在此結
點插入一個關鍵字時.FlemsOnNode值加1.當刪除一個關鍵字時.則FlemsOnNode值減1.每個
結l從上可存儲的關鍵字個數介J幾1 } M axElem之間.bf為平衡因r.其作用等同J幾AV1.樹的平
衡因r. MAV1.樹的任一結l從的平衡因r只能取一1 ,0和1.如果一個結l從的平衡因r的絕對
值大」幾1.則這棵樹就失去了平衡.需要做平衡運算保持平衡.lehild和:child分別為指向左右
J"樹根結0的指針.Flems[ i]為結0中第i個關鍵字項.Flems} MaxFlem」是一個按升序排列的
關鍵字數組.具體的MAV1.樹結l從結構如圖1所示.
}lemsOnNode一h『一* leh;ld一
圖1
reh擊3
}lemsi 0}一
樹結點結構
}lemsi Max}lem}
MAVT
MAV1.樹的結構特l從使它比AV1.樹具有更高的存儲效率.在AV1.樹或MAV1.樹中.實際
有用的信急只有關鍵字.1f1! ElemsOnNode ,bf ,lehild和:child都是為了構建樹型結構If1J不得不添
加的輔助信急. MAV1.樹就是通過減小這些輔助信急的比例來獲得較高的存儲效率.山MAV1.
樹結l從的定義可以看出:FlemsOnNode和bf為int型.各,片4個位元組長度.指針型的lchild和
rchild也各,片4個位元組長度.在以上四項信急中.AV1.樹結l從除了沒有ElemsOnNode外.其餘和
MAV1.樹相同.現假設關鍵字長度為24位元組.M axFl二值定為50.則對AV1.樹來說.它的結l從
長度為36位元組.其中輔助信h,長度為12位元組;If}J MAV1.樹的結l從長度是1. 2K位元組.其中輔助
信急長度為16位元組.山此可以看出.MAV1.樹在存儲時.結l從中輔助信急長度,片整個結l從長度
的比例是很小的.它對存儲空間的利用效率比 AV1.樹要高.這一l從對」幾主要而向內存應用的
MAV1.樹來說是非常重要的.
在實際的應用中.當MAV1.樹作為資料庫索引結構時.為進一步節約內存空間.結l從中Fl-
emType的結構可根據實際需要作不同的定義.
( 1)當排序關鍵字較短時.可以直接將資料庫中的關鍵字值拷貝到索引文件中.這樣
MAV1.樹既有較快的運行速度又不會,片用太大的空間.此時ElemType定義如卜
struct IdxRlemStruct
{
int RecPos://金己錄號
KeyType Key://關鍵字
}R1emType;
( 2}當排序關鍵字較長時.如果直接將資料庫中的關鍵字值拷貝到索引文件中會,片據較大
的空間.此時可以採用只存儲關鍵字地址的形式.這樣不管關鍵字有多長.映射到MAV1.樹後
都只,片據一個指針的固定長度.這種以時間換空間的方法比較適合內存容量有限的情況.此時
ElemType定義如卜
struct Tdxl?lemStruct
int RecPos:
char * Key
R1emType;
//記錄號
//關鍵字指釗
3基於MAUI.樹的運算
MAUI.樹的基木運算.包括MAUI.樹的建立、記錄的插入、刪除、修改以及查詢.這些演算法
與基J幾AVI.樹的演算法相似.都建立在一叉查詢和平衡演算法基礎上.
3. 1 MAVI,樹的平衡運算
如果在一棵原木是平衡的MAUI.樹中插入一個新結l從.造成了不平衡.此時必須調整樹的
結構.使之平衡化「21 .MAUI.樹的平衡演算法與AVI.樹的平衡演算法是相同的.但山J幾MAUI.樹的
每個結l從中都存儲有多個關鍵字.所以在關鍵字個數相同的情況卜. MAUI.樹的應用可以大大
減少平衡運算的次數.例如.假設具有n個關鍵字的待插入序列在插入過程中有5%(根據隨
機序列特l從的不同.此數值會有所差異.這里以比較保守的5%為例)的新產生結l從會導致一
叉樹出現不平衡.對AVI.樹來說.山」幾需要為每個關鍵字分配一個結l從.所以在整個插入過程
中做平衡的次數為n * 5%;對J幾MAUI.樹.設MAUI.樹中M axFl二的值被定義為k(k為大J幾1
的正整數少,則平均每k次的數據插入才會有一個新結l從產生,所以在整個插入過程中需做平
衡的次數僅為(nlk) * 5%.即在M axFl二取值為k的情況卜.對」幾相同的待插入關鍵字序列.
在插入過程中MAUI.樹用J幾平衡運算的開銷是AVI.樹的1/ k.
3. 2數據查找
在MAUI.樹上進行查找.是一個從根結l從開始.沿某一個分支逐層向卜進行比較判等的過
程.假設要在MAUI.樹上查找的值為GetKey.查找過程從根結l從開始.如果根指針為NU1.1..則
查找失敗;否則把要查找的值GetKey與根結l從關鍵字數組中的最小項Elems [ 0]進行比較.如
果GetKev小」幾當前結i最小關鍵字.則遞歸查找左r樹;如果GetKey'大」幾Elems [ 0].則將
GetKey'與根結0關鍵字數組中的最大項Fletns} MaxFl二一1]進行比較.如果GetKey'大」幾當前
結l從最大關鍵字.則遞歸查找右r樹;否則.對當前結l從的關鍵字數組進行查找(山」幾是有序序
列.可以採用折半查找以提高效率).如果有與GetKey'相匹配的值.則查找成功.返回成功信
息,7{報告查找到的關鍵字地址.
3. 3數據插入
數據插入是構建MAV1.樹的基礎.設要在MAV1.樹*T上插入一個新的數據兀素GetKev,
其遞歸演算法描述如卜:
(1)若*T為空樹.則申清一新結} ' Elems} MaxElem}.將GetKey'插入到Flems[ 0]的位置.樹
的深度增1.
(2)若*T未滿.則在*T中找到插入位置後將GetKey'插入.JI在插入後保持結l從中的各
關鍵項有序遞增.若己存在與GetKev相同的項.則不進行插入.
(3)如果*T為滿結l從目一GetKey'值介」幾Flems[ 0]和Flems} MaxFlem]之間.則在*T中找到
GetKev的插入位置posit ion.山」幾*T木身就是滿結l從.所以GetKev的插入必然會將原來*T中
的某個數據擠出去JI卜降到r樹中.根據插入位置position的不同.分以卜幾種情況處理:若*
T中存在與C etl} e`'相同的項.則不進行插入;若插入位置在*T結ii的前半部分(即position <
=MaxFlem/ 2).則將Flems[ 1]到Fletns} position」的數據依次左移一位.再把GetKey插入到Elems
} MaxFlem」中position的位置.Ifn原來*T中最左邊項數據將被擠入到*T的左r樹中.考察此
數據的特l從.它必然大」幾*T左r樹中的任一數據項.所以此時不需要作任何的額外運算.直
接將此數據插入到*T左r樹根結i從的最右r孫位置處就可以了(見圖2中插入,}} 11"後「1,>
的位置變化);若插入位置在*T結ii的後半部分(即position> MaxFlem/ 2).則將Fletns} posi-
tion}到Fletns} MaxFl二一2}的數據依次右移一位.再把GetKev插入到*T結0中position的位
置.與前一種情況類似.結l從中最右邊被擠出的項將被插入到*T的右r樹根結l從的最左r孫
的位置(見圖2中插入「25"後" 30"的位置變化).
插入,"}i」插入」zs0
}o i is i }a
s}土 s
圖2
滿結點插入數據的過程
(4)若GetKey的值小」幾T的最小項值.則將GetKey遞歸插入到T的左r樹中.即在遞歸調
用時GetKey值不變Ifn T= T->lehild.
(5)若GetKey的值大」幾T的最大項值.則將GetKey遞歸插入到T的右r樹中.即在遞歸調
用時GetKey值不變Ifn T= T->rehild.
4結束語
山J幾MAV1.樹的結l從中存儲有多個關鍵字值.所以它具有較高的存儲效率;對MAV l樹進
行查找是_分查找和順序查找的結合.其查詢效率只略低」幾AV1.樹.血山」幾MAV1.樹的平衡
運算比AV1.樹要少得多.所以MAV1.樹有很優秀的綜合運算效率.綜上所述.在數據量大、內
存容量相對較小、數據增刪運算比較頻繁的情況卜.用MAV1.樹作為常駐內存的索引結構是一
種理想的選擇.
G. 動平衡計算
允許不平衡量的計算公式為:M*e=mper*r,轉子的偏心距e=G*1000/ω,轉子的角速度ω=2πn/60。
上述計算公式中mper為允許不平衡量,M代表轉子的自身重量,單位是kg;G代表轉子的平衡精度等級 ,單位是mm/s;ω代表轉子的角速度,單位是弧度/秒;r代表轉子的校正半徑,單位是mm;n代表轉子的工作轉速,單位是rpm;e代表轉子的偏心距,單位是μm。
(7)平衡演算法擴展閱讀:
平衡時的轉速和工作轉速不一致,造成平衡精度下降。例如:有不少轉子屬於二階臨界轉速的擾性轉子,由於平衡機本身轉速有限,這些轉子若採用工藝平衡,則無法有效地防止轉子在高速下發生變形而造成的不平衡。
有些轉子,由於受到尺寸和重量上的限制,很難甚至無法在平衡機上平衡。例如:對於大型發電機及透平一類的特大轉子,由於沒有相應的特大平衡裝置,往往會造成無法平衡。
H. SSD平衡磨損演算法的疑問
SSD裝得越滿,速度就越受影響,這個是沒錯的。因為負載平衡演算法要用到剩餘空間,但SandForce主控受這個影響較大,而M4影響不大。
至於你一開始說的那個極端情況,也不是簡單這樣分析。通常主控會把頻繁讀寫的熱數據平攤到每個顆粒每個區塊。長遠來看,這樣性能會很受影響(因為平衡磨損均攤會造成大量地址變動),但對壽命而言,50MB熱數據只是毛毛雨。
對於你的實際情況,請注意一點:讀,是幾乎不產生磨損的;寫,才影響壽命。SSD主控的使命是兼顧性能和壽命,沒事的時候吃飽了撐的去挪動超大文件?無論如何,主控不可能為了磨損平均度就玩命地搬移數據,平攤的過程本身就要造成讀寫,這方面SSD會有自己的演算法來做到平衡。記住一點,壽命到時基本所有顆粒的磨損度都差不多!不可能給你造成只有某個顆粒讀寫特別厲害的情況。更何況還有預留空間,即使有顆粒超出預期地早掛,還有備份的頂上。
關於你說的WIN7後台挪動的問題,我只問你一句:相比winxp,win7才有的trim指令是干嗎的?不就是為了SSD後台智能優化,恢復性能回收可用地址的嘛!這一切都是無聲智能的。而且你要明白,一個超大的系統文件可能地址都分散映射在不同的SSD顆粒裡面,即使為了磨損平衡,也只要變動很少一部分地址而已,沒必要整個挪動大文件的。
對於你的補充,相信你現在也該明白了,如果在這種極端情況下,SSD主控會逐漸把不動的那些數據小部分小部分轉移,讓這100M的讀寫磨損盡量平均分布到所有顆粒上,了解?
PS:所以我當初狠狠心,直接上M4 128G了,系統盤丟進去,魔獸丟進去,還剩60G不到空間,乾脆再把所有應用軟體通通扔進去,這下能加速的都加速了,剩餘空間也足夠,壽命也好速度也好都妥妥的。
建議你去PCEVA論壇固態硬碟板塊看看,版大對SSD的講解深入淺出,以後看到OCZ之流的動輒5,600M速度就能一眼看穿貓膩在哪裡。很慶幸,選了鎂光,選了M4~