最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

【TIS-100 攻略】TIS-NET 第 1 關(guān):序列合并器

2022-10-31 22:04 作者:ココアお姉ちゃん  | 我要投稿

本文首發(fā)于 B 站《TIS-100》文集(https://www.bilibili.com/read/readlist/rl626023)。原創(chuàng)不易,轉(zhuǎn)載請注明出處。

恭喜你完成了 TIS-100 SEGMENT MAP 系列里的所有關(guān)卡,現(xiàn)在請點擊右上角的【TIS-100 NET DIRECTORY】按鈕,開始挑戰(zhàn)難度更大的 TIS-NET 系列關(guān)卡。

TIS-NET 第 1 關(guān)《序列合并器》(Sequence Merger)關(guān)卡展示

IN.A 和 IN.B 會不斷給你提供一些以 0 結(jié)尾的序列(兩者長度不一定相等)。你收到的兩個序列里的數(shù)字都已按從小到大的順序排好序。請你將 IN.A 和 IN.B 這兩個序列合并成一個序列,同時確保合并后的序列仍然有序。

將兩個序列里的數(shù)都放進(jìn)棧里,再使用第 21 關(guān)的做法對棧里的數(shù)字排序是一種容易想到的做法。但問題在于,本關(guān)的兩個棧相隔太遠(yuǎn),傳話非常不便。而且這樣做也沒有利用【得到的序列已經(jīng)有序】這樣的特征。

其實,兩個有序數(shù)組合并成一個數(shù)組,是有專門的算法的,這叫做【雙指針?biāo)惴ā俊蓚€指針 i、j 一開始分別指向兩個數(shù)組的頭部,然后我們比較兩個數(shù)字的大小,選擇其中較小的一項輸出,然后指向較小項的指針向后移動,指向較大項的指針不動。中途若有一個指針指向了數(shù)組末端,那么剩下的元素就全從另一個數(shù)組里拿。如圖所示:

初始狀態(tài)下,指針 i 和指針 j 都指向了各自數(shù)組的頭部
第 1 步,j 指向的 1 比 i 指向的 2 小,所以提取出 j 指向的 1,指針 j 后移一格
第 2 步:j 指向的 1 比 i 指向的 2 小,所以提取出 j 指向的 1,指針 j 后移一格
第 3 步:i 指向的 2 比 j 指向的 3 小,所以提取出 i 指向的 2,指針 i 后移一格
第 4 步:i 指向的 3 和 j 指向的 3 一樣大,任選一項均可。這里選擇了上面的?3,指針 i 后移一格
第 5 步:j 指向的 3 比 i 指向的 4 小,所以提取出 j 指向的 3,指針 j 后移一格
第 6 步:i 指向的 4 比 j 指向的 6 小,所以提取出 i 指向的 4,指針 i 后移一格
第 7 步:數(shù)組 A 的最后三個 5 都比 j 指向的 6 小,所以將數(shù)組 A 的后三個 5 提取出來,指針 i 指到了數(shù)組末端,指針 j 不動
第 8 步:由于指針 i 指到了數(shù)組 A 的末端,數(shù)組 A 已沒有數(shù)字可用,只剩下數(shù)組 B 里的最后三個數(shù)可用。因此將數(shù)組 B 里的最后三個數(shù)加入到合并數(shù)組的末尾。至此兩個有序數(shù)組就合并成了一個數(shù)組,且合并后的數(shù)組依然有序。

我們將以上算法寫成 C 語言代碼(a?和 b?數(shù)組一定以 0 結(jié)尾,表示數(shù)組的末端):

以上的算法里,兩個數(shù)組的哨兵都是 0??紤]到每次都是選擇兩個目標(biāo)數(shù)中的較小數(shù),如果我們把哨兵換成一個足夠大的數(shù)(比如 999),那么當(dāng)其中一個量到達(dá)數(shù)組末端,另一個量卻沒到達(dá)時,比較大小時就一直是另一個小,我們在合并的時候就不需要特殊判定兩個指針是否指到了末端。當(dāng)兩者中的較小值都為 999 時,我們自然會知道,兩個指針都指向了末端,此時輸出最后的 0。改進(jìn)后的算法代碼如下:

現(xiàn)在我們將以上 C 語言代碼轉(zhuǎn)寫成 TIS-100 的匯編代碼,如下:

本關(guān)用到了?6?個節(jié)點,我分別用它們所在的方向(左上、右上、左、中、右、下)來指代。

左上和左下的節(jié)點分別把?IN.A 和 IN.B 提供的值發(fā)給中路靠左和中路靠右的節(jié)點(mov up down)。接下來是中路靠左的節(jié)點:

  1. 中路靠左的節(jié)點會收到左上發(fā)來的【指針 i 所指向的數(shù)】,即 a[i],將它存入 acc(mov up acc)。

  2. 此時判斷收到的數(shù)是否為哨兵 0。若不是哨兵?0,跳到第 4 行執(zhí)行(jnz 4),

  3. 否則令 acc 加上 999,將哨兵 0 變?yōu)樯诒?999(add 999)。

  4. 到了第 4 行后,左節(jié)點會將 a[i] 的值發(fā)給中央節(jié)點(mov acc right),

  5. 然后聽從中央節(jié)點的指令(jro right)。中央節(jié)點發(fā)送 -1 時,表示保留住當(dāng)前的 a[i],指針 i 不向后移動,那么我們就跳回第 4 行,繼續(xù)向中央節(jié)點發(fā)送當(dāng)前的 a[i];而當(dāng)中央節(jié)點發(fā)送 -4 時,表示丟棄掉當(dāng)前的 a[i],指針 i 向后移動,那么我們就跳回第 1 行,從左上節(jié)點接收下一個?a[i]。

接下來看中路靠右的節(jié)點:

  1. 中路靠右的節(jié)點會收到右上發(fā)來的【指針 j 所指向的數(shù)】,即 b[j],將它存入 acc(mov up acc)。

  2. 此時判斷收到的數(shù)是否為哨兵 0。若不是哨兵 0,跳到第 4 行執(zhí)行(jnz 4),

  3. 否則令 acc 加上 999,將哨兵 0 變?yōu)樯诒?999(add 999)。

  4. 到了第 4 行后,右節(jié)點會將 b[j] 的值向中央節(jié)點發(fā)兩遍(mov acc left)

  5. (mov acc left)。我們在之前的攻略里反復(fù)強調(diào)了:取出兩者中的較?。^大值時,其中一方必然要將自己的數(shù)提供兩遍。我的代碼里選擇了把 b[j] 提供兩遍,其實改為把 a[i] 提供兩遍的話,道理也是一樣的。

  6. 把 b[j] 發(fā)送兩遍后,右節(jié)點開始聽從中央節(jié)點的指令(jro left)。中央節(jié)點發(fā)送 -2 時,表示保留住當(dāng)前的 b[j],指針 j 不向后移動,那么我們就跳回第 4?行,繼續(xù)向中央節(jié)點發(fā)送當(dāng)前的 b[j];而當(dāng)中央節(jié)點發(fā)送 -5 時,表示丟棄掉當(dāng)前的 b[j],指針 j 向后移動,那么我們就跳回第 1 行,從右上節(jié)點接收下一個 b[j]。

中央節(jié)點是算法的核心部分。

  1. 首先我們計算 a[i]?和 b[j] 的差值(mov left acc)

  2. (sub right)

  3. 差值大于 0 時,跳到第 11 行執(zhí)行(jgz b)。

  4. 那么第 4 行僅當(dāng)差值小于等于 0 時能執(zhí)行到。差值小于等于?0 時,我們肯定是輸出 a[i] 并令指針 i 后移。首先必然給左邊節(jié)點發(fā)送 -4,讓左邊節(jié)點丟棄掉當(dāng)前的 a[i](mov -4 left)。

  5. 然后我們注意到,中央節(jié)點的 acc 的值是 a[i] - b[j] 的值,此時我們加回右邊節(jié)點第二次提供的 b[j],讓 acc 變成 a[i] - b[j] + b[j] = a[i](add right)。

  6. 到了這一步,我們還不能直接輸出這個值,我們需要進(jìn)一步判定 a[i] 是不是哨兵 999。因此我們再將 acc 減去 999(sub 999)并判定 acc 是否變成了 0。

  7. 如果變成了 0,說明 i、j 指針都指向了各自的末端,右邊節(jié)點自然也要把當(dāng)前的 b[j] 給丟棄掉。acc 為 0 時,我們空降到第 13 行,給右邊節(jié)點發(fā)送 -5,讓右邊節(jié)點丟棄掉當(dāng)前的 b[j],并將最后的 0 往下發(fā)(jez d, mov -5 right, mov acc down)。

  8. acc 不為 0 時,說明 i 指針尚未到達(dá) a 數(shù)組的末端,a[i] 并不是哨兵 999。這時候只有 i 指針向后移動,j 指針不變,我們按照規(guī)則,向右邊節(jié)點發(fā)送 -2,令右邊節(jié)點保持當(dāng)前的 b[j] 不動(mov -2 right)。

  9. 接著我們將 acc 加回一個 999,得到原始的 a[i] 值(add 999),

  10. 然后跳過第 11~13 行的互斥邏輯,直接空降到第 14 行,將得到的 a[i] 值往下發(fā)(jmp e, mov acc down)。

  11. 第 11~13 行僅當(dāng) a[i] - b[j] 的差值大于 0 時才能執(zhí)行到。差值大于 0 時,說明 b[j] 比 a[i] 小,那么當(dāng)前項我們自然是輸出較小的 b[j],并令 j 指針向后移動。我們從右邊節(jié)點拿到第二次提供的 b[j],放入 acc 暫存(mov right?acc)。

  12. 接下來,i 指針不動,按照規(guī)則,向左邊節(jié)點發(fā)送 -1,令左邊節(jié)點保持當(dāng)前的 a[i] 不動(mov -1 left);

  13. j 指針需要后移一格,按照規(guī)則,向右邊節(jié)點發(fā)送 -5,令右邊節(jié)點丟棄掉當(dāng)前的 b[j](mov -5 right)。

  14. 最后,我們將 acc 中的值發(fā)給下方節(jié)點(mov acc down)。

下方的節(jié)點沒啥好說的,老老實實把中央節(jié)點傳來的數(shù)送給 OUT.S 端口就 OK 了(mov up down)。

點擊左下角的【RUN】,稍等片刻,便會彈出結(jié)算界面:


【TIS-100 攻略】TIS-NET 第 1 關(guān):序列合并器的評論 (共 條)

分享到微博請遵守國家法律
雅江县| 株洲市| 博白县| 辽源市| 栖霞市| 阿拉善右旗| 家居| 宜丰县| 武汉市| 泸溪县| 温州市| 徐闻县| 贵定县| 拉孜县| 龙岩市| 会理县| 林芝县| 德州市| 涿州市| 额尔古纳市| 融水| 宁城县| 色达县| 靖安县| 朝阳区| 巴楚县| 凤翔县| 普安县| 广南县| 金阳县| 新泰市| 德兴市| 德州市| 靖远县| 乃东县| 蕲春县| 台安县| 谢通门县| 成都市| 怀远县| 淳化县|