首出演算法塊
⑴ 採用首次適應演算法回收內存時,可能出現哪幾種情況應該怎樣處理這些情況 採用首次適應演算法
a. 回收區與插入點的前一個分區相鄰接,此時可將回收區與插入點的前一分區合並,不再為回收分區分配新表項,而只修改前鄰接分區的大小;
b. 回收分區與插入點的後一分區相鄰接,此時合並兩區,然後用回收區的首址作為新空閑區的首址,大小為兩者之和;
c. 回收區同時與插入點的前後兩個分區鄰接,此時將三個分區合並,使用前鄰接分區的首址,大小為三區之和,取消後鄰接分區的表項;
d. 回收區沒有鄰接空閑分區,則應為回收區單獨建立一個新表項,填寫回收區的首址和大小,並根據其首址,插入到空閑鏈中的適當位置
⑵ 高速緩沖存儲器的作用是什麼
高速緩沖存儲器的容量一般只有主存儲器的幾百分之一,但它的存取速度能與中央處理器相匹配。
根據程序局部性原理,正在使用的主存儲器某一單元鄰近的那些單元將被用到的可能性很大。因而,當中央處理器存取主存儲器某一單元時,計算機硬體就自動地將包括該單元在內的那一組單元內容調入高速緩沖存儲器,中央處理器即將存取的主存儲器單元很可能就在剛剛調入到高速緩沖存儲器的那一組單元內。
所以中央處理器就可以直接對高速緩沖存儲器進行存取。在整個處理過程中,如果中央處理器絕大多數存取主存儲器的操作能為存取高速緩沖存儲器所代替,計算機系統處理速度就能顯著提高。
(2)首出演算法塊擴展閱讀:
提高高速緩沖存儲器讀取命中率的演算法:
1、隨機法:隨機替換演算法就是用隨機數發生器產生一個要替換的塊號,將該塊替換出去,此演算法簡單、易於實現,而且它不考慮Cache塊過去、現在及將來的使用情況,但是沒有利用上層存儲器使用的「歷史信息」、沒有根據訪存的局部性原理。
2、先進先出法:先進先出演算法就是將最先進入Cache的信息塊替換出去。FIFO演算法按調入Cache的先後決定淘汰的順序,選擇最早調入Cache的字塊進行替換,它不需要記錄各字塊的使用情況,比較容易實現,系統開銷小。
3、近期最少使用法:近期最少使用(Least Recently Used,LRU)演算法。這種方法是將近期最少使用的Cache中的信息塊替換出去。該演算法較先進先出演算法要好一些。但此法也不能保證過去不常用將來也不常用。
⑶ 區塊鏈 --- 共識演算法
PoW演算法是一種防止分布式服務資源被濫用、拒絕服務攻擊的機制。它要求節點進行適量消耗時間和資源的復雜運算,並且其運算結果能被其他節點快速驗算,以耗用時間、能源做擔保,以確保服務與資源被真正的需求所使用。
PoW演算法中最基本的技術原理是使用哈希演算法。假設求哈希值Hash(r),若原始數據為r(raw),則運算結果為R(Result)。
R = Hash(r)
哈希函數Hash()的特性是,對於任意輸入值r,得出結果R,並且無法從R反推回r。當輸入的原始數據r變動1比特時,其結果R值完全改變。在比特幣的PoW演算法中,引入演算法難度d和隨機值n,得到以下公式:
Rd = Hash(r+n)
該公式要求在填入隨機值n的情況下,計算結果Rd的前d位元組必須為0。由於哈希函數結果的未知性,每個礦工都要做大量運算之後,才能得出正確結果,而算出結果廣播給全網之後,其他節點只需要進行一次哈希運算即可校驗。PoW演算法就是採用這種方式讓計算消耗資源,而校驗僅需一次。
PoS演算法要求節點驗證者必須質押一定的資金才有挖礦打包資格,並且區域鏈系統在選定打包節點時使用隨機的方式,當節點質押的資金越多時,其被選定打包區塊的概率越大。
POS模式下,每個幣每天產生1幣齡,比如你持有100個幣,總共持有了30天,那麼,此時你的幣齡就為3000。這個時候,如果你驗證了一個POS區塊,你的幣齡就會被清空為0,同時從區塊中獲得相對應的數字貨幣利息。
節點通過PoS演算法出塊的過程如下:普通的節點要成為出塊節點,首先要進行資產的質押,當輪到自己出塊時,打包區塊,然後向全網廣播,其他驗證節點將會校驗區塊的合法性。
DPoS演算法和PoS演算法相似,也採用股份和權益質押。
但不同的是,DPoS演算法採用委託質押的方式,類似於用全民選舉代表的方式選出N個超級節點記賬出塊。
選民把自己的選票投給某個節點,如果某個節點當選記賬節點,那麼該記賬節點往往在獲取出塊獎勵後,可以採用任意方式來回報自己的選民。
這N個記賬節點將輪流出塊,並且節點之間相互監督,如果其作惡,那麼會被扣除質押金。
通過信任少量的誠信節點,可以去除區塊簽名過程中不必要的步驟,提高了交易的速度。
拜占庭問題:
拜占庭是古代東羅馬帝國的首都,為了防禦在每塊封地都駐扎一支由單個將軍帶領的軍隊,將軍之間只能靠信差傳遞消息。在戰爭時,所有將軍必須達成共識,決定是否共同開戰。
但是,在軍隊內可能有叛徒,這些人將影響將軍們達成共識。拜占庭將軍問題是指在已知有將軍是叛徒的情況下,剩餘的將軍如何達成一致決策的問題。
BFT:
BFT即拜占庭容錯,拜占庭容錯技術是一類分布式計算領域的容錯技術。拜占庭假設是對現實世界的模型化,由於硬體錯誤、網路擁塞或中斷以及遭到惡意攻擊等原因,計算機和網路可能出現不可預料的行為。拜占庭容錯技術被設計用來處理這些異常行為,並滿足所要解決的問題的規范要求。
拜占庭容錯系統 :
發生故障的節點被稱為 拜占庭節點 ,而正常的節點即為 非拜占庭節點 。
假設分布式系統擁有n台節點,並假設整個系統拜占庭節點不超過m台(n ≥ 3m + 1),拜占庭容錯系統需要滿足如下兩個條件:
另外,拜占庭容錯系統需要達成如下兩個指標:
PBFT即實用拜占庭容錯演算法,解決了原始拜占庭容錯演算法效率不高的問題,演算法的時間復雜度是O(n^2),使得在實際系統應用中可以解決拜占庭容錯問題
PBFT是一種狀態機副本復制演算法,所有的副本在一個視圖(view)輪換的過程中操作,主節點通過視圖編號以及節點數集合來確定,即:主節點 p = v mod |R|。v:視圖編號,|R|節點個數,p:主節點編號。
PBFT演算法的共識過程如下:客戶端(Client)發起消息請求(request),並廣播轉發至每一個副本節點(Replica),由其中一個主節點(Leader)發起提案消息pre-prepare,並廣播。其他節點獲取原始消息,在校驗完成後發送prepare消息。每個節點收到2f+1個prepare消息,即認為已經准備完畢,並發送commit消息。當節點收到2f+1個commit消息,客戶端收到f+1個相同的reply消息時,說明客戶端發起的請求已經達成全網共識。
具體流程如下 :
客戶端c向主節點p發送<REQUEST, o, t, c>請求。o: 請求的具體操作,t: 請求時客戶端追加的時間戳,c:客戶端標識。REQUEST: 包含消息內容m,以及消息摘要d(m)。客戶端對請求進行簽名。
主節點收到客戶端的請求,需要進行以下交驗:
a. 客戶端請求消息簽名是否正確。
非法請求丟棄。正確請求,分配一個編號n,編號n主要用於對客戶端的請求進行排序。然後廣播一條<<PRE-PREPARE, v, n, d>, m>消息給其他副本節點。v:視圖編號,d客戶端消息摘要,m消息內容。<PRE-PREPARE, v, n, d>進行主節點簽名。n是要在某一個范圍區間內的[h, H],具體原因參見 垃圾回收 章節。
副本節點i收到主節點的PRE-PREPARE消息,需要進行以下交驗:
a. 主節點PRE-PREPARE消息簽名是否正確。
b. 當前副本節點是否已經收到了一條在同一v下並且編號也是n,但是簽名不同的PRE-PREPARE信息。
c. d與m的摘要是否一致。
d. n是否在區間[h, H]內。
非法請求丟棄。正確請求,副本節點i向其他節點包括主節點發送一條<PREPARE, v, n, d, i>消息, v, n, d, m與上述PRE-PREPARE消息內容相同,i是當前副本節點編號。<PREPARE, v, n, d, i>進行副本節點i的簽名。記錄PRE-PREPARE和PREPARE消息到log中,用於View Change過程中恢復未完成的請求操作。
主節點和副本節點收到PREPARE消息,需要進行以下交驗:
a. 副本節點PREPARE消息簽名是否正確。
b. 當前副本節點是否已經收到了同一視圖v下的n。
c. n是否在區間[h, H]內。
d. d是否和當前已收到PRE-PPREPARE中的d相同
非法請求丟棄。如果副本節點i收到了2f+1個驗證通過的PREPARE消息,則向其他節點包括主節點發送一條<COMMIT, v, n, d, i>消息,v, n, d, i與上述PREPARE消息內容相同。<COMMIT, v, n, d, i>進行副本節點i的簽名。記錄COMMIT消息到日誌中,用於View Change過程中恢復未完成的請求操作。記錄其他副本節點發送的PREPARE消息到log中。
主節點和副本節點收到COMMIT消息,需要進行以下交驗:
a. 副本節點COMMIT消息簽名是否正確。
b. 當前副本節點是否已經收到了同一視圖v下的n。
c. d與m的摘要是否一致。
d. n是否在區間[h, H]內。
非法請求丟棄。如果副本節點i收到了2f+1個驗證通過的COMMIT消息,說明當前網路中的大部分節點已經達成共識,運行客戶端的請求操作o,並返回<REPLY, v, t, c, i, r>給客戶端,r:是請求操作結果,客戶端如果收到f+1個相同的REPLY消息,說明客戶端發起的請求已經達成全網共識,否則客戶端需要判斷是否重新發送請求給主節點。記錄其他副本節點發送的COMMIT消息到log中。
如果主節點作惡,它可能會給不同的請求編上相同的序號,或者不去分配序號,或者讓相鄰的序號不連續。備份節點應當有職責來主動檢查這些序號的合法性。
如果主節點掉線或者作惡不廣播客戶端的請求,客戶端設置超時機制,超時的話,向所有副本節點廣播請求消息。副本節點檢測出主節點作惡或者下線,發起View Change協議。
View Change協議 :
副本節點向其他節點廣播<VIEW-CHANGE, v+1, n, C , P , i>消息。n是最新的stable checkpoint的編號, C 是 2f+1驗證過的CheckPoint消息集合, P 是當前副本節點未完成的請求的PRE-PREPARE和PREPARE消息集合。
當主節點p = v + 1 mod |R|收到 2f 個有效的VIEW-CHANGE消息後,向其他節點廣播<NEW-VIEW, v+1, V , O >消息。 V 是有效的VIEW-CHANGE消息集合。 O 是主節點重新發起的未經完成的PRE-PREPARE消息集合。PRE-PREPARE消息集合的選取規則:
副本節點收到主節點的NEW-VIEW消息,驗證有效性,有效的話,進入v+1狀態,並且開始 O 中的PRE-PREPARE消息處理流程。
在上述演算法流程中,為了確保在View Change的過程中,能夠恢復先前的請求,每一個副本節點都記錄一些消息到本地的log中,當執行請求後副本節點需要把之前該請求的記錄消息清除掉。
最簡單的做法是在Reply消息後,再執行一次當前狀態的共識同步,這樣做的成本比較高,因此可以在執行完多條請求K(例如:100條)後執行一次狀態同步。這個狀態同步消息就是CheckPoint消息。
副本節點i發送<CheckPoint, n, d, i>給其他節點,n是當前節點所保留的最後一個視圖請求編號,d是對當前狀態的一個摘要,該CheckPoint消息記錄到log中。如果副本節點i收到了2f+1個驗證過的CheckPoint消息,則清除先前日誌中的消息,並以n作為當前一個stable checkpoint。
這是理想情況,實際上當副本節點i向其他節點發出CheckPoint消息後,其他節點還沒有完成K條請求,所以不會立即對i的請求作出響應,它還會按照自己的節奏,向前行進,但此時發出的CheckPoint並未形成stable。
為了防止i的處理請求過快,設置一個上文提到的 高低水位區間[h, H] 來解決這個問題。低水位h等於上一個stable checkpoint的編號,高水位H = h + L,其中L是我們指定的數值,等於checkpoint周期處理請求數K的整數倍,可以設置為L = 2K。當副本節點i處理請求超過高水位H時,此時就會停止腳步,等待stable checkpoint發生變化,再繼續前進。
在區塊鏈場景中,一般適合於對強一致性有要求的私有鏈和聯盟鏈場景。例如,在IBM主導的區塊鏈超級賬本項目中,PBFT是一個可選的共識協議。在Hyperledger的Fabric項目中,共識模塊被設計成可插拔的模塊,支持像PBFT、Raft等共識演算法。
Raft基於領導者驅動的共識模型,其中將選舉一位傑出的領導者(Leader),而該Leader將完全負責管理集群,Leader負責管理Raft集群的所有節點之間的復制日誌。
下圖中,將在啟動過程中選擇集群的Leader(S1),並為來自客戶端的所有命令/請求提供服務。 Raft集群中的所有節點都維護一個分布式日誌(復制日誌)以存儲和提交由客戶端發出的命令(日誌條目)。 Leader接受來自客戶端的日誌條目,並在Raft集群中的所有關注者(S2,S3,S4,S5)之間復制它們。
在Raft集群中,需要滿足最少數量的節點才能提供預期的級別共識保證, 這也稱為法定人數。 在Raft集群中執行操作所需的最少投票數為 (N / 2 +1) ,其中N是組中成員總數,即 投票至少超過一半 ,這也就是為什麼集群節點通常為奇數的原因。 因此,在上面的示例中,我們至少需要3個節點才能具有共識保證。
如果法定仲裁節點由於任何原因不可用,也就是投票沒有超過半數,則此次協商沒有達成一致,並且無法提交新日誌。
數據存儲:Tidb/TiKV
日誌:阿里巴巴的 DLedger
服務發現:Consul& etcd
集群調度:HashiCorp Nomad
只能容納故障節點(CFT),不容納作惡節點
順序投票,只能串列apply,因此高並發場景下性能差
Raft通過解決圍繞Leader選舉的三個主要子問題,管理分布式日誌和演算法的安全性功能來解決分布式共識問題。
當我們啟動一個新的Raft集群或某個領導者不可用時,將通過集群中所有成員節點之間協商來選舉一個新的領導者。 因此,在給定的實例中,Raft集群的節點可以處於以下任何狀態: 追隨者(Follower),候選人(Candidate)或領導者(Leader)。
系統剛開始啟動的時候,所有節點都是follower,在一段時間內如果它們沒有收到Leader的心跳信號,follower就會轉化為Candidate;
如果某個Candidate節點收到大多數節點的票,則這個Candidate就可以轉化為Leader,其餘的Candidate節點都會回到Follower狀態;
一旦一個Leader發現系統中存在一個Leader節點比自己擁有更高的任期(Term),它就會轉換為Follower。
Raft使用基於心跳的RPC機制來檢測何時開始新的選舉。 在正常期間, Leader 會定期向所有可用的 Follower 發送心跳消息(實際中可能把日誌和心跳一起發過去)。 因此,其他節點以 Follower 狀態啟動,只要它從當前 Leader 那裡收到周期性的心跳,就一直保持在 Follower 狀態。
當 Follower 達到其超時時間時,它將通過以下方式啟動選舉程序:
根據 Candidate 從集群中其他節點收到的響應,可以得出選舉的三個結果。
共識演算法的實現一般是基於復制狀態機(Replicated state machines),何為 復制狀態機 :
簡單來說: 相同的初識狀態 + 相同的輸入 = 相同的結束狀態 。不同節點要以相同且確定性的函數來處理輸入,而不要引入一下不確定的值,比如本地時間等。使用replicated log是一個很不錯的注意,log具有持久化、保序的特點,是大多數分布式系統的基石。
有了Leader之後,客戶端所有並發的請求可以在Leader這邊形成一個有序的日誌(狀態)序列,以此來表示這些請求的先後處理順序。Leader然後將自己的日誌序列發送Follower,保持整個系統的全局一致性。注意並不是強一致性,而是 最終一致性 。
日誌由有序編號(log index)的日誌條目組成。每個日誌條目包含它被創建時的任期號(term),和日誌中包含的數據組成,日誌包含的數據可以為任何類型,從簡單類型到區塊鏈的區塊。每個日誌條目可以用[ term, index, data]序列對表示,其中term表示任期, index表示索引號,data表示日誌數據。
Leader 嘗試在集群中的大多數節點上執行復制命令。 如果復製成功,則將命令提交給集群,並將響應發送回客戶端。類似兩階段提交(2PC),不過與2PC的區別在於,leader只需要超過一半節點同意(處於工作狀態)即可。
leader 、 follower 都可能crash,那麼 follower 維護的日誌與 leader 相比可能出現以下情況
當出現了leader與follower不一致的情況,leader強制follower復制自己的log, Leader會從後往前試 ,每次AppendEntries失敗後嘗試前一個日誌條目(遞減nextIndex值), 直到成功找到每個Follower的日誌一致位置點(基於上述的兩條保證),然後向後逐條覆蓋Followers在該位置之後的條目 。所以丟失的或者多出來的條目可能會持續多個任期。
要求候選人的日誌至少與其他節點一樣最新。如果不是,則跟隨者節點將不投票給候選者。
意味著每個提交的條目都必須存在於這些伺服器中的至少一個中。如果候選人的日誌至少與該多數日誌中的其他日誌一樣最新,則它將保存所有已提交的條目,避免了日誌回滾事件的發生。
即任一任期內最多一個leader被選出。這一點非常重要,在一個復制集中任何時刻只能有一個leader。系統中同時有多餘一個leader,被稱之為腦裂(brain split),這是非常嚴重的問題,會導致數據的覆蓋丟失。在raft中,兩點保證了這個屬性:
因此, 某一任期內一定只有一個leader 。
當集群中節點的狀態發生變化(集群配置發生變化)時,系統容易受到系統故障。 因此,為防止這種情況,Raft使用了一種稱為兩階段的方法來更改集群成員身份。 因此,在這種方法中,集群在實現新的成員身份配置之前首先更改為中間狀態(稱為聯合共識)。 聯合共識使系統即使在配置之間進行轉換時也可用於響應客戶端請求,它的主要目的是提升分布式系統的可用性。
⑷ 求用c語言寫出首次適應分配演算法的分配過程~
/********************************
內存管理模擬程序
*******************************/
#include<iostream.h>
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include <time.h>
#include <windows.h>
/*定義宏*/
#define TotalMemSize 1024 /*劃分的物理塊的大小,地址范圍0~1023*/
#define MinSize 2 /*規定的不再分割的剩餘分區的大小*/
#define getpch(type) (type*)malloc(sizeof(type))
/*定義內存塊*/
typedef struct memBlock
{
struct memBlock *next;/*指向下一個塊*/
int stAddr; /*分區塊的初始地址*/
int memSize; /*分區塊的大小*/
int status; /*分區塊的狀態,0:空閑,1:以被分配*/
}MMB;
/*定義全局變數*/
MMB *idleHead=NULL; /*空閑分區鏈表的頭指針*/
MMB *usedHead=NULL; /*分配分區鏈表的頭指針*/
MMB *usedRear=NULL; /*分配分區鏈表的鏈尾指針*/
MMB *np; /*循環首次適應演算法中指向即將被查詢的空閑塊*/
int idleNum=1;/*當前空閑分區的數目*/
int usedNum=0;/*當前已分配分區的數目*/
MMB *memIdle=NULL; /*指向將要插入分配分區鏈表的空閑分區*/
MMB *memUsed=NULL; /*指向將要插入空閑分區鏈表的已分配分區*/
int flag=1;/*標志分配是否成功,1:成功*/
/*函數聲明*/
void textcolor (int color);/*輸出著色*/
void InitMem();/*初始化函數*/
int GetUseSize(float miu,float sigma); /*獲得請求尺寸*/
MMB *SelectUsedMem(int n);/*選擇待釋放的塊*/
void AddToUsed();/*將申請到的空閑分區加到分配分區鏈表中*/
int RequestMemff(int usize); /*請求分配指定大小的內存,首次適應演算法*/
int RequestMemnf(int usize); /*請求分配指定大小的內存,循環首次適應演算法*/
void AddToIdle();/*將被釋放的分配分區加到空閑分區鏈表中(按地址大小)*/
void ReleaseMem(); /*釋放指定的分配內存塊*/
/*主函數*/
void main()
{
int sim_step;
float miu,sigma; /*使隨機生成的請求尺寸符合正態分布的參數*/
int i;
int a;
MMB *p;
/* double TotalStep=0,TotalSize=0,TotalRatio=0,TotalUSize=0,Ratio=0,n=0;
double aveStep=0,aveSize=0,aveRatio=0;
int step=0,usesize=0; */
textcolor(11);
printf("\n\t\t內存管理模擬程序\n\n");
/* InitMem();*/
while(true)
{
double TotalStep=0,TotalSize=0,TotalRatio=0,TotalUSize=0,Ratio=0,n=0;
double aveStep=0,aveSize=0,aveRatio=0;
int step=0,usesize=0;
InitMem();
textcolor(12);
printf("\n\n首次適應演算法: 0");
printf("\n循環首次適應演算法: 1\n");
textcolor(11);
printf("\n請選擇一種演算法:");
scanf("%d",&a);
textcolor(15);
printf("\n輸入一定數量的步數:(sim_step)");
scanf("%d",&sim_step);
printf("\n 輸入使隨機生成的請求尺寸符合正態分布的參數:miu,sigma ");
scanf("%f,%f",&miu,&sigma);
for(i=1;i<=sim_step;i++)
{
textcolor(10);
printf("\n\n#[%d]\n",i);
do{
usesize=GetUseSize(miu,sigma);
while((usesize<0)||(usesize>TotalMemSize))
{
usesize=GetUseSize(miu,sigma);
}
textcolor(13);
printf("\n\n申請的內存尺寸為:%d",usesize);
printf("\n此時可用的空閑分區有 %d 塊情況如下:",idleNum);
p=idleHead;
textcolor(15);
while(p!=NULL)
{
printf("\n始址:%d\t 尺寸:%d",p->stAddr,p->memSize);
p=p->next;
}
TotalSize+=usesize;
if(a==0)
step=RequestMemff(usesize);
else
step=RequestMemnf(usesize);
TotalStep+=step;
n++;
}while(flag==1);
p=usedHead;
while(p!=NULL)
{
TotalUSize+=p->memSize;
printf("\n始址:%d\t 尺寸:%d",p->stAddr,p->memSize);
p=p->next;
}
textcolor(11);
if(TotalUSize!=0)
{
Ratio=TotalUSize/TotalMemSize;
TotalUSize=0;
printf("\n內存利用率NO.%d :%f%c",i,100*Ratio,'%');
}
else
{
Ratio=0;
printf("\n內存利用率NO.%d :%c%c",i,'0','%');
}
TotalRatio+=Ratio;
ReleaseMem();
}
if(n!=0)
{
textcolor(10);
aveStep=TotalStep/n;
aveSize=TotalSize/n;
aveRatio=TotalRatio/sim_step;
printf("\n平均搜索步驟:%f",aveStep);
printf("\n平均請求尺寸:%f",aveSize);
printf("\n平均內存利用率:%f",aveRatio);
}
}
}
// 輸出著色 /////////////////////////////////////////
void textcolor (int color)
{
SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), color );
}
/******************************
函數名:InitMem()
用途:把內存初始化為一整塊空閑塊
****************************************/
void InitMem()
{
MMB *p;
p=getpch(MMB);
p->memSize=TotalMemSize;
p->stAddr=0;
p->status=0;
p->next=NULL;
idleHead=p;
np=idleHead;
usedHead=NULL;
usedRear=NULL;
idleNum=1;
usedNum=0;
flag=1;
memIdle=NULL;
memUsed=NULL;
}
/******************************
函數名:GetUseSize(float miu,float sigma)
用途:獲得請求尺寸;
參數說明:float miu,float sigma :正態分布的參數
返回值:申請尺寸的大小;
****************************************************/
int GetUseSize(float miu,float sigma)
{
float r1,r2;
float u,v,w;
float x,y;
do
{
r1=rand()/32767.0;
r2=rand()/32767.0;
u=2*r1-1;
v=2*r2-1;
w=u*u+v*v;
}while(w>1);
x=u*sqrt(((-log(w))/w));
y=v*sqrt(((-log(w))/w));
return miu+sigma*x;
}
/******************************
函數名:*SelectUsedMem(int n)
用途:選擇待釋放的塊(0~n-1)
返回值:指向待釋放的塊的指針;
****************************************************/
MMB *SelectUsedMem(int n)
{
MMB *p;
int i,j;
if(n>0)
{
i = rand()%n ;
textcolor(5);
printf("\n\n當前已分配分區總數為:%d",n);
printf("\n待釋放塊的序號為:%d\n",i );
p=usedHead;
if(p!=NULL)
{
for(j=i;j>0;j--)
p=p->next;
return(p);
}
else
return(NULL);
}
else
{
printf("\n當前沒有可釋放的資源!\n");
}
}
/******************************
函數名:AddToUsed()
用途:將申請到的空閑分區加到分配分區鏈表中
***************************************************************/
void AddToUsed()
{
MMB *p;
memIdle->status=1;
if(usedHead==NULL)
{
usedHead=memIdle;
usedRear=usedHead;
}
else
{
usedRear->next=memIdle;
usedRear=memIdle;
}
usedNum++;
printf("\n當前分配分區共有%d塊!",usedNum);
p=usedHead;
while(p!=NULL)
{
printf("\n始址:%d \t 尺寸:%d",p->stAddr,p->memSize);
p=p->next;
}
}
/******************************
函數名:RequestMemff(int usize)
參數說明:usize:請求尺寸的大小;
用途:請求分配指定大小的內存,首次適應演算法
返回值:搜索步驟
***************************************************************/
int RequestMemff(int usize)
{
MMB *p1,*p2,*s;
int step;
int suc=0;
int size1,size2;
if(idleHead==NULL)
{
flag=0;
textcolor(12);
printf("\n分配失敗!");
return 0;
}
else
{
if((idleHead->memSize)>usize)
{
size1=(idleHead->memSize)-usize;
if(size1<=MinSize)
{
memIdle=idleHead;
idleHead=idleHead->next;
memIdle->next=NULL;
idleNum--;
}
else
{
s=getpch(MMB);
s->memSize=usize;
s->stAddr=idleHead->stAddr;
s->status=1;
s->next=NULL;
memIdle=s;
idleHead->memSize=idleHead->memSize-usize;
idleHead->stAddr=idleHead->stAddr+usize;
}
step=1;
flag=1;
textcolor(12);
printf("\n分配成功!");
AddToUsed();
}
else
{
p1=idleHead;
step=1;
p2=p1->next;
while(p2!=NULL)
{
if((p2->memSize)>usize)
{
size2=(p2->memSize)-usize;
if(size2<=MinSize)
{
p1->next=p2->next;
memIdle=p2;
memIdle->next=NULL;
idleNum--;
}
else
{
s=getpch(MMB);
s->memSize=usize;
s->stAddr=p2->stAddr;
s->status=1;
s->next=NULL;
memIdle=s;
p2->memSize=p2->memSize-usize;
p2->stAddr=p2->stAddr+usize;
}
flag=1;
suc=1;
textcolor(12);
printf("\n分配成功!");
AddToUsed();
p2=NULL;
}
else
{
p1=p1->next;
p2=p2->next;
step++;
}
}
if(suc==0)
{
flag=0;
textcolor(12);
printf("\n分配失敗!");
}
}
}
return step;
}
/******************************
函數名:AddToIdle()
用途:將被釋放的分配分區加到空閑分區鏈表中(按地址遞增順序排列)
***************************************************************/
void AddToIdle()
{
MMB *p1,*p2;
int insert=0;
if((idleHead==NULL))
{
idleHead=memUsed;
idleNum++;
np=idleHead;
}
else
{
int Add=(memUsed->stAddr)+(memUsed->memSize);
if((memUsed->stAddr<idleHead->stAddr)&&(Add!=idleHead->stAddr))
{
memUsed->next=idleHead;
idleHead=memUsed;
idleNum++;
}
else
{
if((memUsed->stAddr<idleHead->stAddr)&&(Add==idleHead->stAddr))
{
idleHead->stAddr=memUsed->stAddr;
idleHead->memSize+=memUsed->memSize;
}
else
{
p1=idleHead;
p2=p1->next;
while(p2!=NULL)
{
if(memUsed->stAddr>p2->stAddr)
{
p1=p1->next;
p2=p2->next;
}
else
{
int Add1=p1->stAddr+p1->memSize;
int Add2=p2->stAddr-memUsed->memSize;
if((Add1==memUsed->stAddr)&&(memUsed->stAddr!=Add2))
{
p1->memSize=p1->memSize+memUsed->memSize;
}
if((Add1!=memUsed->stAddr)&&(memUsed->stAddr==Add2))
{
p2->memSize=p2->memSize+memUsed->memSize;
p2->stAddr=memUsed->stAddr;
}
if((Add1!=memUsed->stAddr)&&(memUsed->stAddr!=Add2))
{
memUsed->next=p2;
p1->next=memUsed;
if(np->stAddr==p2->stAddr)
np=p1->next;
idleNum++;
}
if((Add1==memUsed->stAddr)&&(memUsed->stAddr==Add2))
{
p1->memSize=p1->memSize+memUsed->memSize+p2->memSize;
p1->next=p2->next;
if((np->stAddr)==(p2->stAddr))
np=p1;
idleNum--;
}
p2=NULL;
insert=1;
}
}
if(insert==0)
{
p1->next=memUsed;
idleNum++;
}
}
}
}
}
/******************************
函數名:ReleaseMem()
用途:釋放指定的分配內存塊
***************************************************************/
void ReleaseMem()
{
MMB *q1,*q2;
MMB *s;
if(usedNum==0)
{
printf("\n當前沒有分配分區!");
return;
}
else
{
s=SelectUsedMem(usedNum);
if(s!=NULL)
{
if(s->stAddr==usedHead->stAddr)
{
memUsed=usedHead;
usedHead=usedHead->next;
memUsed->next=NULL;
AddToIdle();
usedNum--;
}
else
{
q1=usedHead;
q2=q1->next;
while(q2!=NULL)
{
if(q2->stAddr!=s->stAddr)
{
q1=q1->next;
q2=q2->next;
}
else
{
q1->next=q2->next;
memUsed=q2;
memUsed->next=NULL;
if(q1->next==NULL)
usedRear=q1;
AddToIdle();
usedNum--;
q2=NULL;
}
}
}
}
}
}
/******************************
函數名:RequestMemnf(int usize)
參數說明:usize:請求尺寸的大小;
用途:請求分配指定大小的內存,循環首次適應演算法
返回值:搜索步驟
***************************************************************/
int RequestMemnf(int usize)
{
MMB *p2,*p,*s;
int step;
int iNum=0;
int suc=0;
int size1,size2,size3;
if(idleHead==NULL)
{
flag=0;
printf("\n分配失敗!");
return 0;
}
else
{
iNum=idleNum;
while(iNum>0)
{
iNum--;
if((np->memSize)>usize)
{
/*指針指向的空閑塊滿足條件,且正好為頭指針*/
if(np->stAddr==idleHead->stAddr)
{
size1=(idleHead->memSize)-usize;
if(size1<=MinSize)
{
memIdle=idleHead;
idleHead=idleHead->next;
memIdle->next=NULL;
idleNum--;
}
else
{
s=getpch(MMB);
s->memSize=usize;
s->stAddr=idleHead->stAddr;
s->status=1;
s->next=NULL;
memIdle=s;
idleHead->memSize=idleHead->memSize-usize;
idleHead->stAddr=idleHead->stAddr+usize;
}
if((idleHead==NULL)||(idleHead->next==NULL))
np=idleHead;
else
np=idleHead->next;
}
else/*指針指向的空閑塊滿足條件,不為頭指針*/
{
size2=(np->memSize)-usize;
if(size2<=MinSize) /*從空閑鏈表中刪除*/
{
p=idleHead;
while(p->next->stAddr!=np->stAddr)
p=p->next;
p->next=np->next;
memIdle=np;
memIdle->next=NULL;
np=p;
idleNum--;
}
else
{
s=getpch(MMB);
s->memSize=usize;
s->stAddr=np->stAddr;
s->status=1;
s->next=NULL;
memIdle=s;
np->memSize=np->memSize-usize;
np->stAddr=np->stAddr+usize;
}
if(np->next==NULL)
np=idleHead;
else
np=np->next;
}
step=1;
flag=1;
suc=1;
textcolor(12);
printf("\n分配成功!");
AddToUsed();
iNum=0;
}
else /*當前指針指向的空閑區不滿足條件*/
{
step=1;
p2=np->next;
if(p2==NULL)
{
np=idleHead;
iNum--;
}
else
{
if((p2->memSize)>usize)
{
size3=(p2->memSize)-usize;
if(size3<=MinSize)
{
np->next=p2->next;
memIdle=p2;
memIdle->next=NULL;
idleNum--;
}
else
{
s=getpch(MMB);
s->memSize=usize;
s->stAddr=p2->stAddr;
s->status=1;
s->next=NULL;
memIdle=s;
p2->memSize=p2->memSize-usize;
p2->stAddr=p2->stAddr+usize;
}
flag=1;
suc=1;
printf("\n分配成功!");
AddToUsed();
if(p2->next==NULL)
np=idleHead;
else
np=p2->next;
p2=NULL;
iNum=0;
}
else
{
np=np->next;
p2=p2->next;
iNum--;
step++;
}
}
}
// iNum--;
}
if(suc==0)
{
flag=0;
textcolor(12);
printf("\n分配失敗!");
}
}
return step;
}
⑸ 採用c語言實現首次適應演算法完成主存空間的分配和回收 急
有沒有具體的要求,比方說數據結構方面,我這有一個,你可以參考參考
#include"stdio.h"
#include"stdlib.h"
#define
n
10
/*假定系統允許的最大作業為n,假定模擬實驗中n值為10*/
#define
m
10
/*假定系統允許的空閑區表最大為m,假定模擬實驗中m值為10*/
#define
minisize
100
struct{
float
address;
/*已分分區起始地址*/
float
length;
/*已分分區長度,單位為位元組*/
int
flag;
/*已分配區表登記欄標志,用"0"表示空欄目*/
}used_table[n];
/*已分配區表*/
struct{
float
address;
/*空閑區起始地址*/
float
length;
/*空閑區長度,單位為位元組*/
int
flag;
/*空閑區表登記欄標志,用"0"表示空欄目,用"1"表示未分配*/
}free_table[m];
/*空閑區表*/
void
main(
)
{
int
i,a;
void
allocate(char
str,float
leg);//分配主存空間函數
void
reclaim(char
str);//回收主存函數
float
xk;
char
J;/*空閑分區表初始化:*/
free_table[0].address=10240;
free_table[0].length=102400;
free_table[0].flag=1;
for(i=1;i<m;i++)
free_table[i].flag=0;/*已分配表初始化:*/
for(i=0;i<n;i++)
used_table[i].flag=0;
while(1)
{
printf("\n選擇功能項(0-退出,1-分配主存,2-回收主存,3-顯示主存)\n");
printf("選擇功項(0~3)
:");
scanf("%d",&a);
switch(a)
{
case
0:
exit(0);
/*a=0程序結束*/
case
1:
/*a=1分配主存空間*/printf("輸入作業名J和作業所需長度xk:
");
scanf("%*c%c%f",&J,&xk);
allocate(J,xk);/*分配主存空間*/
break;
case
2:
/*a=2回收主存空間*/printf("輸入要回收分區的作業名");
scanf("%*c%c",&J);reclaim(J);/*回收主存空間*/
break;
case
3:
/*a=3顯示主存情況*//*輸出空閑區表和已分配表的內容*/
printf("輸出空閑區表:\n起始地址
分區長度
標志\n");
for(i=0;i<m;i++)
printf("%6.0f%9.0f%6d\n",free_table[i].address,free_table[i].length,
free_table[i].flag);
printf("
按任意鍵,輸出已分配區表\n");
getchar();
printf("
輸出已分配區表:\n起始地址
分區長度
標志\n");
for(i=0;i<n;i++)
if(used_table[i].flag!=0)
printf("%6.0f%9.0f%6c\n",used_table[i].address,used_table[i].length,
used_table[i].flag);
else
printf("%6.0f%9.0f%6d\n",used_table[i].address,used_table[i].length,
used_table[i].flag);
break;
default:printf("沒有該選項\n");
}/*case*/
}/*while*/
}/*主函數結束*/
int
uflag;//分配表標志
int
fflag;//空閑表標志
float
uend_address;
float
fend_address;
void
allocate(char
str,float
leg)
{
uflag=0;fflag=0;
int
k,i;float
ressize;
for(i=0;i<m;i++)
{
if(free_table[i].flag==1
&&
free_table[i].length>=leg)
{
fflag=1;break;
}
}
if(fflag==0)
printf("沒有滿足條件的空閑區\n");
else
{
ressize=free_table[i].length-leg;
for(k=0;k<n;k++)
{
if(used_table[k].flag==0)
{
if(ressize<minisize)//剩餘塊過小
{
used_table[k].length=free_table[i].length;
used_table[k].address=free_table[i].address;
used_table[k].flag=str;
free_table[i].length=0;
free_table[i].flag=0;
break;
}
else
{
used_table[k].address=free_table[i].address+ressize;
used_table[k].flag=str;
used_table[k].length=leg;
free_table[i].length=ressize;
break;
}
}
}//for結束
}
}
void
reclaim(char
str)
{
uflag=0;fflag=0;
int
k,i;
for(k=0;k<n;k++)
{
if(used_table[k].flag==str)
{
uflag=1;break;
}
}
if(uflag==0)
printf("\n找不到該作業!\n");
else
{
for(i=0;i<m;i++)
{
uend_address=used_table[k].address+used_table[k].length;
fend_address=free_table[i].address+free_table[i].length;
if(used_table[k].address==fend_address)//上鄰
{
fflag=1;
free_table[i].length=free_table[i].length+used_table[k].length;
free_table[i].flag=1;
used_table[k].flag=0;
used_table[k].length=0;
used_table[k].address=0;
printf("\n已回收!\n");
break;
}
else
{
if(free_table[i].address==uend_address)//下鄰
{
fflag=1;
free_table[i].address=used_table[k].address;
free_table[i].length=free_table[i].length+used_table[k].length;
free_table[i].flag=1;
used_table[k].flag=0;
used_table[k].length=0;
used_table[k].address=0;
printf("\n已回收!\n");
break;
}
}
}//for結束
if(fflag==0)
{
i=0;
for(i=0;i<m;i++)
{
if(free_table[i].flag==0)
{
free_table[i].address=used_table[k].address;
free_table[i].length=used_table[k].length;
free_table[i].flag=1;
used_table[k].length=0;
used_table[k].flag=0;
used_table[k].address=0;
break;
}
}
printf("\n已回收!\n");
}
}
}
⑹ 開方的簡便演算法
開方的簡便演算法是:
比如136161這個數字,首先我們找到一個和136161的平方根比較接近的數,任選一個,比方說300到400間的任何一個數,這里選350,作為代表. 我們計算0.5*(350+136161/350)得到369.5 然後我們再計算0.5*(369.5+136161/369.5)得到369.0003,我們發現369.5和369.0003相差無幾,並且,369^2末尾數字為1.我們有理由斷定369^2=136161 一般來說能夠開方開的盡的,用上述方法算一兩次基本結果就出來了。
此方法是在高一學萬有引力和航天時,因需要大量開平方運算又不能用計算器,而被逼無奈研發的。
開立方的方法與開平方的方法很類似,但要復雜很多,如果不能熟練掌握,倒不如按大臉貓說的方法:湊!當然,熟練掌握以後,比湊的方法是快多了。
拓展資料
開方(英文rooting),指求一個數的方根的運算,為乘方的逆運算(參見「方根」詞條)。在中國古代也指求二次及高次方程(包括二項方程)的正根。
⑺ 快遞運費首重續重計算方法
你這兩件貨看快遞公司怎麼收,如果給你按兩票貨算費用就高,如果給你按一票貨算費用就少點,具體費用就是:首重+續重,首重就是第一公司的重量,續重就是減1公斤後後面的重量再算,比如你這兩件貨如果快遞公司一起算一票的話具體演算法是:18.3+13.7=32kg=1(首重)*9+31(續重)*3=102元,一般黑點的快遞公司點要給你按兩票算就是第一箱18.3按19公斤算,因為快遞收費是不足一公斤按一公斤算的也就是18.3=19=1*9+18*3=63元,第二箱13.7=14=1*9+13*3=48元,分開算的話你的費用要多9元,你可以和快遞公司講價全部按一起算,因為你這是算大貨了,還可以講成全按3快一公斤算,對了和EMS不可以講價,其他快遞公司可以講價。
⑻ 演算法設計:順序隊列的結構定義如下,請設計將隊首元素x出隊的演算法,請將出隊函數的函數整體補充完整
具體代碼先不寫了,提供一個思路給你:
將隊列的第一個元素拿出來,放入輔助隊列中
將兩個隊列的第一個元素比較(用Dequeue()方法獲取),大的放入輔助隊列,小的依然放到原始隊列的末尾。
重復(2)的操作,直至所有的元素都比較了一遍
這樣就將原來隊列裡面最大的元素取出來了並保存到了輔助隊列裡面(相應的原始隊列裡面刪除了這個元素),然後再用循環的方法將第二大、第三大的數依次取出......
⑼ 首次適應演算法是什麼
分區分配演算法(Partitioning Placement Algorithm)
最佳適應演算法(Best Fit):
它從全部空閑區中找出能滿足作業要求的、且大小最小的空閑分區,這種方法能使碎片盡量小。為適應此演算法,空閑分區表(空閑區鏈)中的空閑分區要按大小從小到大進行排序,自表頭開始查找到第一個滿足要求的自由分區分配。該演算法保留大的空閑區,但造成許多小的空閑區。
首次適應演算法(First Fit):
從空閑分區表的第一個表目起查找該表,把最先能夠滿足要求的空閑區分配給作業,這種方法目的在於減少查找時間。為適應這種演算法,空閑分區表(空閑區鏈)中的空閑分區要按地址由低到高進行排序。該演算法優先使用低址部分空閑區,在低址空間造成許多小的空閑區,在高地址空間保留大的空閑區。
循環首次適應演算法(Next Fit):
該演算法是首次適應演算法的變種。在分配內存空間時,不再每次從表頭(鏈首)開始查找,而是從上次找到空閑區的下一個空閑開始查找,直到找到第一個能滿足要求的的空閑區為止,並從中劃出一塊與請求大小相等的內存空間分配給作業。該演算法能使內存中的空閑區分布得較均勻。
⑽ vb實現先進先出演算法是什麼
vb實現先進先出演算法是指以先購入的存貨應先發出(銷售或耗用)這樣一種存貨實物流轉假設為前提,對發出存貨進行計價的一種方法。