尚未理解樹以前感受樹很神祕(看過數據結構視頻),樹這種結構看上去很難以想象,究竟是怎麼實現而且操做的,學完二叉樹就感受這操做有點簡單。巧妙經過遞歸就把對樹杈的處理變成了對根和左右孩子的處理。 樹能夠處理大量的數據,可是對數的操做代碼量很少,由於大部分操做使用了遞歸,須要對遞歸有較好的理解,不然代碼很容易出現錯誤,並且很難發現。 樹這個數據結構很是實用,因此必需要掌握,好比目錄,排序等都須要樹,acm也會出現樹的題目。
建表達式樹使用兩個棧分別放樹和運算符,遍歷放表達式的字符串,遇到數字就建一個節點入棧,若是是運算符就要判斷是否優先級,若是比棧頂小,棧頂就能夠拿出來,用該運算符建一個節點,左右孩子爲樹棧最上面的兩個節點。計算表達式,經過樹的後續遍歷就能夠。
void InitExpTree(BTree &T, string str) { 聲明兩個棧,一個樹棧,一個運算符棧 Chsta.push('#')運算符棧入棧一個#號避免爲空 for (遍歷字符串str) { if (若是是數字) { 建節點 Bt->data = str[i] 左右孩子置爲空 Bt->lchild = Bt->rchild = NULL 入樹棧 BTsta.push(Bt) } else 若是是運算符 { 調用Precede函數比較優先級 char result = Precede(Chsta.top(), str[i]); if (若是比運算符棧棧頂大) { 入棧 Chsta.push(str[i]); } else if (若是相等)說明是括號 { 出棧 Chsta.pop(); } else 若是比運算符棧棧頂小 { 用運算符建一個節點 Bt->data = Chsta.top(); Chsta.pop(); 左右孩子爲樹棧頂的兩個 Bt->rchild = BTsta.top(); BTsta.pop(); Bt->lchild = BTsta.top(); BTsta.pop(); 最後入棧 BTsta.push(Bt); } } } while (運算符棧還有運算符) { 用運算符建一個節點 Bt->data = Chsta.top(); Chsta.pop(); 左右孩子爲樹棧頂的兩個 Bt->rchild = BTsta.top(); BTsta.pop(); Bt->lchild = BTsta.top(); BTsta.pop(); 最後入棧 BTsta.push(Bt); } } double EvaluateExTree(BTree T) { double left, right放左孩子和右孩子 if (T == NULL) { return 0; } if (若是是葉子節點) { return T->data-'0' 返回節點值 } 遞歸左孩子 left = EvaluateExTree(T->lchild); 遞歸右孩子 right = EvaluateExTree(T->rchild); 計算 switch (T->data) // 根據b結點作相應運算 { case '+': return left + right; case '-': return left - right; case '*': return left * right; case '/': if (right != 0) return left / right; else { cout<<"divide 0 error!"; // 除0異常退出 exit(0); } } }
Q:沒有考慮括號兩個括號相遇時要出棧ios
該題是應用並查集,每一個俱樂部的成員和該俱樂部第一個成員合併,最後哈希獲得最大的朋友圈人數,爲了減小查找時間,盡力讓節點指向根。
#include <iostream> using namespace std; int stu[30010]定義全局變量 int Find(int x) { if (若是x等於stu[x])說明根是本身 { 返回 stu[x]; } else 繼續遞歸找根 { return stu[x]=Find(stu[x]);儘可能讓節點指向根 } } void add(int a, int b)將a和b合併 { int x = Find(a);查找根 int y = Find(b);查找根 if (x != y)合併 { stu[x] = y; } } int main() { int N, M; cin >> N >> M; for (int i = 1; i <= N; i++) 並查集初始化,根是本身 { stu[i] = i; } for (int i = 0; i < M; i++) { int count,a; cin >> count >> a; int b; for (int j = 0; j < count - 1; j++) { cin >> b; add(a, b);//調用合併函數 } } int max = 0; int myhash[30010] = { 0 };hash求最大朋友圈人數 for (int i = 1; i <= N; i++) { int temp = Find(i);找根 myhash[temp]++;根同樣加一 if (myhash[temp] > max)找最大值 { max = myhash[temp]; } } cout << max; return 0; }
Q:在遞歸時儘可能讓節點都指向根數據結構
這個就是一個哈夫曼樹,使用multiset(set不能存放多個相同數據),multiset是從小到大排序好的,每次取最小兩個數據相加,而後做爲新的元素加入multiset中(固然這兩個得刪除),直到只剩一個數據,用sum記錄全部相加和,sum即爲所求最小花費。
A:此題難點不是在於代碼,而是思路,當時恰好學完哈夫曼樹,而後又有STL的加持,就會顯得很輕鬆就過。ide
題目描述函數
在桌面上有一排硬幣,共NN枚,每一枚硬幣均爲正面朝上。如今要把全部的硬幣翻轉成反面朝上,規則是每次可翻轉任意N-1N−1枚硬幣(正面向上的被翻轉爲反面向上,反之亦然)。求一個最短的操做序列(將每次翻轉N-1枚硬幣成爲一次操做)。學習
輸入輸出格式lua
輸入格式:
一個天然數NN(NN爲不大於100100的偶數)。spa
輸出格式:
第一行包含一個整數SS,表示最少須要的操做次數。接下來的SS行每行分別表示每次操做後桌上硬幣的狀態(一行包含NN個整數(00或11),表示每一個硬幣的狀態:00――正面向上,和11――反面向上,不容許出現多餘空格)。設計
對於有多種操做方案的狀況,則只需字典序最小輸出一種。指針
輸入輸出樣例code
輸入樣例#1: 複製
4
輸出樣例#1: 複製
4
0111
1100
0001
1111
翻n-1枚硬幣,就是有一枚不翻,也能夠理解爲翻一枚
邏輯性的題目通常能夠找出規律性,看上去可能很麻煩可是能夠其實代碼量不多,或者有時候能夠巧妙地藉助STL完成解題。