跳到內容

11|單字反轉

還沒完成只限 C++CPU 時間上限 1 秒

相關主題: C++ 基礎速查

只限 C++|CPU 時間上限 1 秒

讀入好幾行文字,把每一行裡的單字順序反過來再輸出。單字本身的內容不變,只是順序顛倒。

「單字」是指連在一起、中間沒有空格的一串字元,例如 hello、C++、!、x=1; 都各算一個單字。單字之間可能隔著一個或好幾個空格,一行的開頭和結尾也可能有空格;輸出時一律只用一個空格分隔單字,開頭和結尾不要有空格。

這一題要練習 C++ 處理字串的基本工具:用 std::getline 一次讀一整行、用 std::istringstream 把一行拆成單字、用 std::vector<std::string> 把單字存起來。用 C 做同一件事要自己開固定大小的字元陣列、用 fgets 讀、再用 strtok 或手動掃描切單字,還得擔心陣列夠不夠大;用 C++ 會簡單很多。

  • 好幾行文字,一直讀到輸入結束 (EOF)。至少 1 行,最多 1000 行。
  • 每行最多 1000 個字元(不含換行),只會出現可印出的 ASCII 字元(英文、數字、符號、空格),不會有 Tab。
  • 可能有空行,或整行都是空格的行。
  • 最後一行後面不一定有換行。

輸入有幾行,輸出就有幾行,順序和輸入相同。每一行輸出該行的單字反過來的結果,單字之間用一個空格分隔。

如果某一行是空行或整行都是空格(沒有任何單字),就輸出一個空行。

輸入:

hello world
the quick brown fox
one
I love C++ !

輸出:

world hello
fox brown quick the
one
! C++ love I

空格在上面看不出來,用 · 代表空格再看一次輸入:

hello·world
··the·quick···brown·fox··
one
···
I·love·C++·!
  • 第 2 行開頭、結尾各有 2 個空格,quick 和 brown 之間有 3 個空格;輸出時都變成一個空格分隔。
  • 第 4 行是空行,第 5 行只有 3 個空格,兩行都輸出空行。
  • C++ 和 ! 都只是一般的單字。

C++:

  • std::getline(std::cin, line) 讀一整行到 std::string(不含換行)。放在 while (...) 的條件裡,讀到 EOF 就會停
  • std::istringstream in(line); 把一個字串當成輸入來源,之後就能用 in >> word 一個一個讀單字;>> 會自動跳過任意數量的空白
  • std::vector<std::string>:可以一直 push_back 的字串陣列,不用事先知道有幾個
  • 範圍 for 迴圈:for (const std::string& w : words),依序走過每個元素;const & 表示只讀、不複製
  • std::reverse(v.begin(), v.end())(在 <algorithm>)可以把整個 vector 倒過來;也可以用索引從最後一個往前走

對照 C:

  • C 要先開 char line[1002]; 這種固定大小的陣列,用 fgets 讀,讀進來的字串最後會留著 '\n'
  • 切單字要用 strtok(line, " ")(會修改原字串)或自己一個字元一個字元掃描
  • 存單字要再開一個二維陣列或指標陣列,還要自己記住有幾個
提示 1:怎麼一直讀到輸入結束?
std::string line;
while (std::getline(std::cin, line)) {
// 處理 line
}

在終端機手動測試時,打完所有行之後按 Ctrl+Z 再按 Enter 代表輸入結束。比較方便的做法是直接拿測試檔當輸入(在 E:\C++ 的終端機輸入):

run exercises\2-cpp\11-reverse-words\main.cpp --input exercises\2-cpp\11-reverse-words\tests\01.in
提示 2:怎麼把一行拆成單字?

#include <sstream> 之後:

std::istringstream in(line);
std::string word;
while (in >> word) {
// 每次拿到一個單字,連續空格會被自動跳過
}

空行或全是空格的行,這個迴圈一次都不會執行。

提示 3:怎麼反過來印、而且單字之間只有一個空格?

先把單字都 push_back 進 std::vector<std::string> words,再從最後一個印到第一個(或先 std::reverse)。

處理分隔空格的常見寫法:用一個 bool first = true;,除了第一個單字以外,每個單字前面先印一個空格。不管這一行有沒有單字,最後都要印 '\n',空行才不會不見。