題目描述:
把紙條豎着放在桌面上,然後從紙條的下邊向上對摺,壓出摺痕後再展開。如果每次都從下邊向上對摺,對摺N次。
我們規定,對於每條摺痕,如果突起的方向指向紙條的背面,那麼這條摺痕叫做“下”摺痕 ;相反,突起的方向指向紙條正面的摺痕叫做“上”摺痕。
請從上到下打印所有摺痕的方向。
分析:
當紙條從下向上對摺一次後打開,有一條摺痕,向下,記爲0。
繼續再向上對摺一次,打開後,在原來0號摺痕上下各出現一條新摺痕,上邊摺痕向下,記爲1號。下邊摺痕向上,記爲2號。
繼續再向上對摺一次,打開後,在1號摺痕和2號摺痕上下各出現一條新摺痕,仍舊上邊向下,下邊向上。
結論:
由以上分析可以看出,對於每一條摺痕,其上下新產生的摺痕必是:上邊的那條向下,下邊的那條向上。
這樣看來,按照摺痕產生的先後順序,其實是滿二叉樹結構。該二叉樹的特點是:根結點是下,每一個節點的左子結點是下,右子結點是上。該二叉樹的中序遍歷即爲答案。
實現:
我們用一個假想的一維數組來模擬這個滿二叉樹,如果摺疊N次,那麼共有2N-1條摺痕,也就是說,這棵想象中的滿二叉樹,有2N-1個結點。從1開始按層次遍歷標號各結點。顯然,除根結點外,偶數號結點均爲左結點,奇數號結點均爲右結點。也就是說,遇到偶數,就輸出Down,遇到奇數,就輸出Up.
用迭代來實現二叉樹的中序遍歷即可搞定。
函數的形參 Counter就是摺紙的次數。
#include <iostream>
#include <cmath>
#include <stack>
//使用中序遍歷滿二叉樹
//這裏的完全二叉樹(其實是滿二叉樹)用數組表示
void printLineUpDown(int Counter)
{
if(Counter < 1)
return;
else if(1 == Counter)
{
endl(std::cout << "Down");
return;
}
unsigned NodeCount = pow(2, Counter) - 1;
std::stack<unsigned int> s;
unsigned int tree = 1;
while(tree <= NodeCount || !s.empty())
{
while(tree <= NodeCount)
{
s.push(tree);
tree *= 2;
}
tree = s.top();
s.pop();
if(0 == tree%2 || 1 == tree)
endl(std::cout << "Down");
else
endl(std::cout << "Up");
//因爲中序遍歷,只要訪問了當前結點,那麼其左子樹已訪問完畢
//讓tree指向當前結點的右子結點
tree *= 2;
tree++;
}
}
由上述代碼分析,壓棧的最大深度即爲該二叉樹的高度,也就是摺紙的次數,故該算法空間複雜度爲O(logN),時間複雜度爲O(N)。