什么是并行計算?
并行計算(Parallel Computing)是指同時使用多種計算資源解決計算問題的程序,是 提高計算機系統計算速度和處理能力的一種有效手段,它的基本思想是用多個處理器來 協同求解同一問題,即將被求解的問題分解成若干個部分,各部分均由一個獨立的處理 機來并行計算,并行計算系統既可以是專門設計的、含有多個處理器的超級計算機,也 可以是以某種方式互連的若干臺的獨立計算機構成的集群,通過并行計算集群完成資料 的處理,再將處理的結果回傳給用戶,
并行計算可分為時間上的并行和空間上的并行,
時間上的并行:是指流水線技術,比如說工廠生產食品的時候步驟分為:
1. 清洗:將食品沖洗干凈,
2. 消毒:將食品進行消毒處理,
3. 切割:將食品切成小塊,
4. 包裝:將食品裝入包裝袋,
如果不采用流水線,一個食品完成上述四個步驟后,下一個食品才進行處理,耗時且影 響效率,但是采用流水線技術,就可以同時處理四個食品,這就是并行演算法中的時間并 行,在同一時間啟動兩個或兩個以上的操作,大大提高計算性能,
空間上的并行:是指多個處理機并發的執行計算,即通過網路將兩個以上的處理機連接起來,達到同時計算同一個任務的不同部分,或者單個處理機無法解決的大型問題,
與10.110.12.29mask 255.255.255.224屬于同一網段的主機IP地址有哪些?
根據你提供的ip地址和掩碼計算出來的ip地址段為10.110.12.0/27.
也就是從10.110.12.0到10.110.12.31.
講一講Makefile的內容.
target - 目標檔案, 可以是 Object File, 也可以是可執行檔案
prerequisites - 生成 target 所需要的檔案或者目標
command - make需要執行的命令 (任意的shell命令), Makefile中的命令必須 以 [tab] 開頭
顯示規則 :: 說明如何生成一個或多個目標檔案(包括 生成的檔案, 檔案的依賴檔案, 生成的命令)
隱晦規則 :: make的自動推導功能所執行的規則
變數定義 :: Makefile中定義的變數
檔案指示 :: Makefile中參考其他Makefile; 指定Makefile中有效部分; 定義一個多行命令
注釋 :: Makefile只有行注釋 “#”, 如果要使用或者輸出"#"字符, 需要進行轉義, “#”
最后,還值得一提的是,在Makefile中的命令,必須要以[Tab]鍵開始,
講一講C++的行內函式
行內函式inline:引入行內函式的目的是為了解決程式中函式呼叫的效率問題,這么說吧,程式在編譯器編譯的時候,編譯器將程式中出現的行內函式的呼叫運算式用行內函式的函式體進行替換,而對于其他的函式,都是在運行時候才被替代,這其實就是個空間代價換時間的i節省,所以行內函式一般都是1-5行的小函式,在使用行內函式時要留神:
1.在行內函式內不允許使用回圈陳述句和開關陳述句;
2.行內函式的定義必須出現在行內函式第一次呼叫之前;
3.類結構中所在的類說明內部定義的函式是行內函式,
vector, deque, list, set, map底層資料結構 vector(向量)——STL中標準而安全的陣列,只能在vector 的“前面”增加資料,
deque(雙端佇列double-ended queue)——在功能上和vector相似,但是可以在前后 兩端向其中添加資料,
list(串列)——游標一次只可以移動一步,如果你對鏈表已經很熟悉,那么STL中的list 則是一個雙向鏈表(每個節點有指向前驅和指向后繼的兩個指標),
set(集合)——包含了經過排序了的資料,這些資料的值(value)必須是唯一的,
map (映射)——經過排序了的二元組的集合,map中的每個元素都是由兩個值組成, 其中的key(鍵值,一個map中的鍵值必須是唯一的)是在排序或搜索時使用,它 的值可以在容器中重新獲取;而另一個值是該元素關聯的數值,比如,除了可以 ar[43] = "overripe"這樣找到一個資料,map還可以通過ar[“banana”] = "overripe"這 樣的方法找到一個資料,如果你想獲得其中的元素資訊,通過輸入元素的全名就可 以輕松實作,
宏定義的優缺點
優點:
-
提高了程式的可讀性,同時也方便進行修改;
-
提高程式的運行效率:使用帶參的宏定義既可完成函式呼叫的功能,又能避免函式的出堆疊與入堆疊操作,減少系統開銷,提高運行效率;
3.宏是由前處理器處理的,通過字串操作可以完成很多編譯器無法實作的功能,比如##連接符,
缺點:
-
由于是直接嵌入的,所以代碼可能相對多一點;
-
嵌套定義過多可能會影響程式的可讀性,而且很容易出錯;
-
對帶參的宏而言,由于是直接替換,并不會檢查引數是否合法,存在安全隱患,

bfs和dfs如何遍歷
1.深度優先搜索(DFS)
原文里的深度優先搜索代碼是有問題的,那是中序遍歷的推廣,而深度優先搜索是先序遍歷的推廣,我這里把兩種代碼都給出來,深度優先搜索的非遞回實作使用了一個堆疊,
深度優先遍歷圖的方法是,從圖中某頂點v出發:
a.訪問頂點v;
b.依次從v的未被訪問的鄰接點出發,對圖進行深度優先遍歷;直至圖中和v有路徑相通的頂點都被訪問;
c.若此時圖中尚有頂點未被訪問,則從一個未被訪問的頂點出發,重新進行深度優先遍歷,直到圖中所有頂點均被訪問過為止,
用一副圖來表達這個流程如下:
1).從v = 頂點1開始出發,先訪問頂點1



2).按深度優先搜索遞回訪問v的某個未被訪問的鄰接點2,頂點2結束后,應該訪問3或5中的某一個,這里為頂點3,此時頂點3不再有出度,因此回溯到頂點2,再訪問頂點2的另一個鄰接點5,由于頂點5的唯一一條邊的弧頭為3,已經訪問了,所以此時繼續回溯到頂點1,找頂點1的其他鄰接點,
上圖可以用鄰接矩陣來表示為:
int maze[][] = {
{ 0, 1, 1, 0, 0 },
{ 0, 0, 1, 0, 1 },
{ 0, 0, 1, 0, 0 },
{ 1, 1, 0, 0, 1 },
{ 0, 0, 1, 0, 0 }
};
具體的代碼如下:
import java.util.LinkedList;
import classEnhance.EnhanceModual;
public class DepthFirst extends EnhanceModual {
@Override
public void internalEntrance() {
// TODO Auto-generated method stub
int maze[][] = {
{ 0, 1, 1, 0, 0 },
{ 0, 0, 1, 0, 1 },
{ 0, 0, 1, 0, 0 },
{ 1, 1, 0, 0, 1 },
{ 0, 0, 1, 0, 0 }
};
dfs(maze, 1);
}
public void dfs(int[][] adjacentArr, int start) {
int nodeNum = adjacentArr.length;
if (start <= 0 || start > nodeNum || (nodeNum == 1 && start != 1)) {
System.out.println("Wrong input !");
return;
} else if (nodeNum == 1 && start == 1) {
System.out.println(adjacentArr[0][0]);
return;
}
int[] visited = new int[nodeNum + 1];//0表示結點尚未入堆疊,也未訪問
LinkedList<Integer> stack = new LinkedList<Integer>();
stack.push(start);
visited[start] = 1;//1表示入堆疊
while (!stack.isEmpty()) {
int nodeIndex = stack.peek();
boolean flag = false;
if(visited[nodeIndex] != 2){
System.out.println(nodeIndex);
visited[nodeIndex] = 2;//2表示結點被訪問
}
//沿某一條路徑走到無鄰接點的頂點
for (int i = 0; i < nodeNum; i++) {
if (adjacentArr[nodeIndex - 1][i] == 1 &&
visited[i + 1] == 0) {
flag = true;
stack.push(i + 1);
visited[i + 1] = 1;
break;//這里的break不能掉!!!!
}
}
//回溯
if(!flag){
int visitedNodeIndex = stack.pop();
}
}
}
}
廣度優先搜索(BFS)
廣度優先搜索是按層來處理頂點,距離開始點最近的那些頂點首先被訪問,而最遠的那些頂點則最后被訪問,這個和樹的層序變數很像,BFS的代碼使用了一個佇列,搜索步驟:
a .首先選擇一個頂點作為起始頂點,并將其染成灰色,其余頂點為白色,
b. 將起始頂點放入佇列中,
c. 從佇列首部選出一個頂點,并找出所有與之鄰接的頂點,將找到的鄰接頂點放入佇列尾部,將已訪問過頂點涂成黑色,沒訪問過的頂點是白色,如果頂點的顏色是灰色,表示已經發現并且放入了佇列,如果頂點的顏色是白色,表示還沒有發現
d. 按照同樣的方法處理佇列中的下一個頂點,
基本就是出隊的頂點變成黑色,在佇列里的是灰色,還沒入隊的是白色,
用一副圖來表達這個流程如下:

1.初始狀態,從頂點1開始,佇列={1}

2.訪問1的鄰接頂點,1出隊變黑,2,3入隊,佇列={2,3,}

3.訪問2的鄰接頂點,2出隊,4入隊,佇列={3,4}

4.訪問3的鄰接頂點,3出隊,佇列={4}

5.訪問4的鄰接頂點,4出隊,佇列={ 空}
分析:
從頂點1開始進行廣度優先搜索:
初始狀態,從頂點1開始,佇列={1}
訪問1的鄰接頂點,1出隊變黑,2,3入隊,佇列={2,3,}
訪問2的鄰接頂點,2出隊,4入隊,佇列={3,4}
訪問3的鄰接頂點,3出隊,佇列={4}
訪問4的鄰接頂點,4出隊,佇列={ 空}
頂點5對于1來說不可達,
上面圖可以用如下鄰接矩陣來表示:
int maze[][] = {
{ 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0 },
{ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 0 }
};
具體的代碼如下,這段代碼有兩個功能,bfs()函式求出從某頂點出發的搜索結果,minPath()函式求從某一頂點出發到另一頂點的最短距離:
import java.util.LinkedList;
import classEnhance.EnhanceModual;
public class BreadthFirst extends EnhanceModual {
@Override
public void internalEntrance() {
// TODO Auto-generated method stub
int maze[][] = {
{ 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0 },
{ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 0 }
};
bfs(maze, 5);//從頂點5開始搜索圖
int start = 5;
int[] result = minPath(maze, start);
for(int i = 1; i < result.length; i++){
if(result[i] !=5 ){
System.out.println("從頂點" + start +"到頂點" +
i + "的最短距離為:" + result[i]);
}else{
System.out.println("從頂點" + start +"到頂點" +
i + "不可達");
}
}
}
public void bfs(int[][] adjacentArr, int start) {
int nodeNum = adjacentArr.length;
if (start <= 0 || start > nodeNum || (nodeNum == 1 && start != 1)) {
System.out.println("Wrong input !");
return;
} else if (nodeNum == 1 && start == 1) {
System.out.println(adjacentArr[0][0]);
return;
}
//0表示頂點尚未入隊,也未訪問,注意這里位置0空出來了
int[] visited = new int[nodeNum + 1];
LinkedList<Integer> queue = new LinkedList<Integer>();
queue.offer(start);
visited[start] = 1;//1表示入隊
while (!queue.isEmpty()) {
int nodeIndex = queue.poll();
System.out.println(nodeIndex);
visited[nodeIndex] = 2;//2表示頂點被訪問
for (int i = 0; i < nodeNum; i++) {
if (adjacentArr[nodeIndex - 1][i] == 1 &&
visited[i + 1] == 0) {
queue.offer(i + 1);
visited[i + 1] = 1;
}
}
}
}
/*
* 從start頂點出發,到圖里各個頂點的最短路徑
*/
public int[] minPath(int[][] adjacentArr, int start) {
int nodeNum = adjacentArr.length;
LinkedList<Integer> queue = new LinkedList<Integer>();
queue.offer(start);
int path = 0;
int[] nodePath = new int[nodeNum + 1];
for (int i = 0; i < nodePath.length; i++) {
nodePath[i] = nodeNum;
}
nodePath[start] = 0;
int incount = 1;
int outcount = 0;
int tempcount = 0;
while (path < nodeNum) {
path++;
while (incount > outcount) {
int nodeIndex = queue.poll();
outcount++;
for (int i = 0; i < nodeNum; i++) {
if (adjacentArr[nodeIndex - 1][i] == 1 &&
nodePath[i + 1] == nodeNum) {
queue.offer(i + 1);
tempcount++;
nodePath[i + 1] = path;
}
}
}
incount = tempcount;
tempcount = 0;
outcount = 0;
}
return nodePath;
}
}
CPU如果訪問記憶體?
通過記憶體管理單元(MMU)
先看一張簡單的CPU訪問記憶體的流程圖:

TLB:轉換lookaside 快取,有了它可以讓虛擬地址到物理地址轉換速度大增,
從上圖中可以清楚的知道了,CPU,DDR,MMU它們三者之間的關系,CPU在MMU開啟的情況下,訪問的都是虛擬地址,
首先通過MMU將虛擬地址轉換為物理地址,
然后再通過總線上去訪問記憶體(我們都知道記憶體是掛在總線上的),
那MMU是怎么將虛擬地址轉換為物理地址呢?當然是通過頁表的方式,MMU從頁表中查出虛擬地址對應的物理地址是什么,然后就去訪問物理記憶體了,
找出在A陣列中,B陣列中沒有的數字,在B陣列中,A陣列中沒有的數字
```cpp
public static void find(int arr[],int[]b){
HashMap<Integer,Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < arr.length; i++) {
map.put(arr[i],0);
}
for (int i=0;i<b.length;i++) {
if(map.containsKey(b[i])){
map.put(b[i],1);
}else{
System.out.println("在B陣列中A不存在的數字");
System.out.println(b[i]);
}
}
for (int i = 0; i <arr.length ; i++) {
if(map.get(arr[i])==0){
System.out.println("在A陣列中存在的,在B陣列不存在的數字");
System.out.println(arr[i]);
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/229853.html
標籤:其他
上一篇:實驗5 linux網路編程
下一篇:計算機網路知識點總結
