2012年3月16日
今天看到《C++ primer》上說:可以用派生類對象初始化基類對象,根據是派生類對象可以賦值給基類的對象的引用。這里我覺得有個語義上的問題:派生類在繼承基類的時候,基類的private成員是不可見的,那么基類初始化private對象的時候,就用了派生類的不可見成員去初始化它了。
先貼段測試代碼:
1 #include<iostream>
2 using namespace std;
3 class A
4 {
5 int mem1,mem2;
6 public:
7 A(const A& a);
8 A(int a, int b):mem1(a),mem2(b){}
9 int fun1(){return mem1;}
10 int fun2(){return mem2;}
11 };
12 A::A(const A& a)
13 {
14 mem1 = a.mem1;
15 mem2 = a.mem2;
16 cout << "A's copy constructor called"<<endl;
17 }
18 class B : public A
19 {
20 int mem3;
21 public:
22 B(int a, int b, int c): A(a,b),mem3(c){}
23 int fun3(){return fun1()};
24 };
25 int main()
26 {
27 B b(1,2,3);
28 A aob(b);
29 }
30
這段代碼輸出:
A's copy constructor called(這是用G++編譯器的,DEV C++ 編譯通過,可是運行沒有輸出)確實如書上說的派生類對象可以賦值給基類的對象的引用,所以調用了拷貝構造函數。其實根據《inside the C++ object model》的說法,派生類的對象中將會保存基類的non-static數據成員的,那么即使不可見,可以用來初始化也在情理之中。
可是再看被初始化對象調用其成員函數的代碼:
1 #include<iostream>
2 using namespace std;
3 class A
4 {
5 int mem1,mem2;
6 public:
7 A(const A& a);
8 A(int a, int b):mem1(a),mem2(b){}
9 int fun1(){return mem1;}
10 int fun2(){return mem2;}
11 };
12 A::A(const A& a)
13 {
14 mem1 = a.mem1;
15 mem2 = a.mem2;
16 cout << "A's copy constructor called"<<endl;
17 }
18 class B : public A
19 {
20 int mem3;
21 public:
22 B(int a, int b, int c): A(a,b),mem3(c){}
23 int fun3(){return fun1()};
24 };
25 int main()
26 {
27 B b(1,2,3);
28 A aob(b);
29 cout <<aob.fun1() << aob.fun2();//the //difference
30 }
31
這就編譯錯誤了:tess.cpp:28:36: error: request for member ‘fun2’ in ‘aob’, which is of non-class type ‘A(B)’這在兩個上述編譯器都是這樣的結果。那么這個對象就無法調用基類的函數了。
我個人膚淺的推斷:A(B)將被編譯器認為是一種新的類型對待,那么怎么確定這種類型的接口函數呢?這不就有問題了嗎?
我再多此一舉的實驗下如下代碼:
1 #include<iostream>
2 using namespace std;
3 class A
4 {
5 int mem1,mem2;
6 public:
7 A(const A& a);
8 A(int a, int b):mem1(a),mem2(b){}
9 int fun1(){return mem1;}
10 int fun2(){return mem2;}
11 };
12 A::A(const A& a)
13 {
14 mem1 = a.mem1;
15 mem2 = a.mem2;
16 cout << "A's copy constructor called"<<endl;
17 }
18 class B : public A
19 {
20 int mem3;
21 public:
22 B(int a, int b, int c): A(a,b),mem3(c){}
23 int fun3(){return fun1();}
24 };
25 int main()
26 {
27 B b(1,2,3);
28 A aob(b);
29 cout <<aob.fun3();// the difference
30 }
31
結果是編譯錯誤:‘class A’ has no member named ‘fun3’這一點也不意外,那么這樣的對象不就真的沒有了接口了?小弟我虛心等待大牛們的解答,希望能在原理上給俺個解釋,不勝感激!
2012年2月24日
今天去面試了個實習,公司需要一個做java web開發的,可是我完全不明白。面試我的人給我個小項目讓我自己做,要我一周內完成,java沒學過,web前端后端什么的也只是聽說,話說那個小項目如果我現學現賣的話也應該不會很難,可是我卻陷入了迷茫:也就是自己發展方向的選擇(需要可以找到相應合適工作的發展方向)的困惑。
我個人的情況是這樣子的:211本科數學專業,學習過網絡,也了解TCP/IP;學習過數據庫,可以熟練的寫SQL;自學過操作系統,覺得挺有趣,還自學了一點體系結構,匯編語言,后來覺得更有趣了;使用了linux,基本的命令行挺熟悉的;計算機語言也就會C/C++,平時寫過一些小東西,實現下一些算法和數學上的東西;用過python寫過一個小作業,發現語言這東西都比較像,區別也就在用途和與機器語言的偏離水平,越是新的語言越是脫離機器底層,也越容易應用;當然數據結構算法之類的也會一些,可惜沒有拿過ACM省級以上的獎。
現在就是不明白有什么方向可以努力的呢?工作?考研?各位工作過的朋友可不可以不吝賜教,給點建議呀!
2012年2月15日
幸福,快樂,happiness這里是同一個詞。
如果一個人可以獲得一些成功,比如我買彩票獲得大獎,比如當年考大學考上了一個好的大學,比如找到一個讓旁人震驚的漂亮女朋友等等。那么人就會感到幸福,這是不可否認的。但是,這樣子的幸福不可能維持很久,不久我們就會習慣了這一切,就如故事里那個擁有花不完財富的國王說他不幸福一樣,我們不會我們已經擁有的一切說是幸福了,即使我們不停地聽到要感恩和知足。我們可能會認為獲得諾貝爾獎將給一個人的一生獲得長久的幸福,而事實是那些獲得諾貝爾獎的人在他們的人生的大部分時間都不會因為自己是諾貝爾獎得主而感到幸福,甚至不會覺得自己有和其他人有什么不同。我們都高估了對那些看似意義深遠的東西所能給我們的幸福感。
有人不停地追求幸福。他們為了幸福的時刻拼盡全力。以至于吸煙,酗酒,乃至于吸毒,濫交,其實這些沒有想象的那么不好,至少可以給人一定時間的滿足感,幸福感,不然也就不會有不少明星,大款喜歡這些,只是社會輿論排斥這些。極限運動也是開始備受推崇,如蹦極,跳傘等等。可是這一切也是會過去的,不過可以給人一定時間是出于幸福的狀態的。
其實我想說人根本就不應該追求幸福!
沒有什么是可以帶來長久的幸福感的!獲得之后就會take it for granted!
所以我們要做甘于過平淡日子的人,他們實際上不會去刻意追求幸福感本身,而是一些有價值和有意義的事。如金錢,家庭和睦,自由等等。
2011年12月28日
如果沒有人告訴你矩陣連乘問題就應該用動態規劃的方法來解決,那么我們應該如何想到呢?
wiki:
動態規劃是這樣子的這里有對矩陣連乘問題的描述。首先應該對問題進行抽象,如果能夠了解問題中矩陣的部分,那么問題可以抽象成這樣
poj1651。這里問題的另一種簡單的表示方式就是:給定一列數,每次你可以從中抽取1個數(除去頭尾兩個數不可以抽取),設置一個score,當你抽取該數的時候,score要加上該數和左右兩個數的乘積,問抽取到最后只剩下頭尾兩個數的時候,怎樣的抽取順序可以使score的值最小呢?
很直觀的方法就是枚舉每種抽取方式,然后找出使score最小的那一次抽取。(這被稱為笨辦法)
先設有n個要抽取的數,也就是總數為n+2。我們試著從中抽取m個,那么我們會發現在省下的那些還沒被抽取的數字中應該存在一種抽取策略使得它們的score最小(
最優子結構,這里可以用簡單的反證法說明),換句話說,就是我們前面怎樣的抽取順序對后面不會造成影響。這里就說明了笨辦法為什么笨了:如果我們找出了后面抽取的最優策略后,那么每次我們改變前面的m個數的抽取順序時,是不需要對后面抽取順序進行枚舉的,只有用最優那個策略即可(
重疊子問題)。
那么這樣說的話,只要找出前面抽取的最優策略和后面抽取的最優策略的話,那么就可以找出這樣的結果:以先抽取m個為分界限的最優解。那么要求抽取n個球的問題時,就需要從1開始到n/2為分界限的最優解。然后再對每個子問題進行遞歸的求解,當n=1時那么問題無需再進行分解。
上面這樣子理解有個缺點:很難用計算機語言實現。問題在于先抽取m個數,這些數的位置不連續。其實把它改為連續的對題目的求解也是一樣的,不過這時候要找的就不是從1到n/2為分界限的最優解了(這樣的話就不全面)。應該從開頭的1,一直到n-1進行找最優解。
這是poj1651的代碼:
1 #include<iostream>
2 using namespace std;
3 const int inf = 0xffffff;
4 int dp[101][101];
5 int num[101];
6 void input(int n){
7 for(int i = 1 ; i <= n; i++)
8 cin>>num[i];
9 for(int i = 0; i <= n; i++)
10 for(int j = 0 ; j <= n; j++)
11 dp[i][j] = inf;
12 }
13 int solve(int a,int b){
14 if(dp[a][b] != inf)return dp[a][b];
15 if(b - a == 2){
16 dp[a][b] = num[a]*num[a+1]*num[b];
17 return dp[a][b];
18 }
19 if(b - a == 1){
20 dp[a][b] = 0;
21 return dp[a][b];
22 }
23 int min = inf;
24 int temp;
25 for(int i = a+1 ; i < b; i ++){
26 temp = solve(a,i) + solve(i,b) + num[a]*num[i]*num[b];
27 if(temp < min) min = temp;
28 }
29 dp[a][b] = min;
30 return dp[a][b];
31 }
32 int main(){
33 int n;
34 while(cin >> n){
35 input(n);
36 cout << solve(1,n)<<endl;
37 }
38 }
回想起以前從事ACM活動,每當有一些題目做不出來,總是會去網上找別人的解題報告。可是
這些解題報告不是寫給人看的:一句dp,二分,線段樹,然后直接就貼了代碼,而且為了追求效率,這些代碼做的優化都很大程度增加了閱讀的難度。比如不寫函數。
poj3070
這道題的意思是通過矩陣的冪來求Fibonacci數列的第n項,且只要求出它的后4位數。
先貼出我認為寫的還是比較清晰的代碼:
1 #include<iostream>
2 using namespace std;
3 class matrix{
4 public:
5 int a[2][2];
6 matrix(){
7 a[0][0]=a[0][1]=a[1][0]=1;
8 a[1][1]=0;
9 }
10 };
11 //矩陣的乘法
12 matrix multi(matrix a,matrix b){
13 matrix temp;
14 for(int i = 0; i < 2; i++)
15 for(int j = 0; j < 2; j++){
16 temp.a[i][j] = 0;
17 for(int k = 0; k < 2;k++)
18 temp.a[i][j] += a.a[i][k]*b.a[k][j];
19 if(temp.a[i][j] >= 10000)
20 temp.a[i][j] %= 10000;//注釋1
21 }
22 return temp;
23 }
24 //矩陣的n次冪
25 matrix power(int n){
26 matrix temp,s;
27 temp.a[1][0] = temp.a[0][1] = 0;
28 temp.a[1][1] = 1;//把temp化成單位矩陣
29 while(n != 0){
30 if(n & 1)
31 temp = multi(temp,s);
32 n = n >> 1;
33 s = multi(s,s);
34 }
35 return temp;
36 }
37 int main(){
38 int n;
39 while(cin >> n && n != -1){
40 matrix ans = power(n);
41 cout << ans.a[1][0] << endl;
42 }
43 }
44
45
46
47
注釋1:為什么可以在每次乘法的取模呢?這是因為:(a*10000+b)*(c*10000+d),即(a*10000+b)和(c*10000+d)這兩個數相乘得到的后四位數是由b,d決定的。那么每次取模也就不影響后四位數了。
在做冪的時候其實體現的就是二分的思想,這可以算是計算機科學中最重要的思想之一了。
其實像我這樣的小菜是有多么希望那些牛人可以花點時間把自己對一道題的理解和思路寫出來,你可以不必每道題都寫出詳細的解題報告,但是你可以在那道沒有人寫詳細思路題上花點時間,這樣可以幫助到很多人!
2011年12月24日
人在每時每刻都在做著決策,那么人是怎樣做出決策的呢?人的大腦有高級的理性部分,也有原始初級的部分。原始初級的部分在幾十萬年的人類進化長河中是通過優勝劣汰所保留下來。其中貪婪,好斗,嫉妒確實對個體在原始社會中獲得了更好的繁殖機會,也就把這部分的基因保存了下來。而近幾百年來,人類的理性大腦在社會進步中起到了非常重要的作用,反過來,人類的生活也受到現代社會的深刻變化的影響。
基本不用懷疑的,在當今社會,如果一個人能受理性思維多一點的控制,他應該能夠在這個以理性和科學的力量而構建起來的世界有更好的適應能力。
回到開頭的問題,人是如何做決策的。人在面對選擇的時候,如果他那時候還能用理性思維控制大腦的話,他應該是這樣做的:首先,他對這件事情在自己或他人的經歷中有沒有出現過(特別是自己),當時理論上最成功的決策應該是什么,然后選取它做為當前事情的決策;如果沒有發生過,那么理性的推導之后得出結論,從而決策。社會的復雜性使人的推導過程必然是不嚴謹的,或者說是人的推導總是有很多假設存在的,但是這總比原始大腦那種潛意識的想法要優質的多。
Ok,決策想好了,接下來就要開始行動了。例如,我決定接下來的一個小時的時間要來看一本數據庫的書。我翻開書,專注的看了15分鐘,在此期間原始大腦發出各種各樣的奇怪的請求(它確實會這樣,而且一直這樣,這畢竟是幾十萬年進化中遺留下來的),我要吃東西,這本書很無聊,我要打游戲,我要很多錢但是不要辛苦,我要美女~~據一項科學研究的結果,人在不是很重要的會議上,1/3的時間是在進行性幻想的。這時候,在不知不覺中,我的大腦的控制權應經交給了原始大腦,而且更加嚴重的問題是,像進程切換沒有保存上下文一樣,我沒有記得自己已經看到了哪里!過了一會理性的大腦回來的時候,我又需要重新開始看!這個時候,原始的大腦又開始發話了,算了吧,那就干脆別看了。這也就是為什么堅持做好一件事情有那么的難。
“該干嘛干嘛去!”這是人們常對自己和一些比較親密的人一句很常見的提醒。這就話有時有一定的功效,歸結其原因還是要看一下這句話的本質是什么:在已經做完決策之后,請你根據理性的大腦的決策一直執行下去吧。
接著,我想說的另一個相關的觀點就是:如果我們是通過深思熟慮而做出的一個中等期限的決策(比如說半年內要學什么,或者準備什么考試),那么請不要輕易改變它或者取消它。Ok,人即使是用理性的大腦做出的決策也是充滿著錯誤和偏見的,那么還有什么必要去為一個不可靠的決策去堅持呢?其實原因很簡單:其一,如果我們推翻自己的結論,那么必然我們需要重新去做一次深思熟慮的決策,那時候的決策不也是一樣的不可靠?其二,在現在的社會,如果一個人想對某一方面有所了解,不用說精通,所需要的時間是不可能很短的。短視,急功近利的原始大腦在原始社會中確實起了作用,但是在現代社會則不那么容易有用了。
2011年12月6日
該程序實現的功能是將一段字符串進行統計之后再進行huffman編碼(二進制);
注意的地方:
1,huffman編碼要用到貪心算法,所以用priority_queue可以在常量時間內取出和插入值。
2,靜態建樹:huffman樹的節點表示方法采用了最多的變量,即父親節點,左右子節點(因為程序中確實有這種需要,這里不同與二叉堆,無法通過在靜態樹(鏈表)的位置來確定其父親節點和子節點);
1 #include<iostream>
2 #include<cstring>
3 #include<queue>
4 #include<cstdlib>
5 using namespace std;
6 const int MAXSIZE = 27;
7 class huffNode{
8 public:
9 int pr;
10 int lc , rc;
11 char s;
12 int pow;
13 bool operator < (const huffNode& b)const{
14 return pow > b.pow;
15 }
16 };
17 huffNode huff[MAXSIZE * 2];
18 string buf;
19 int count[26];
20 priority_queue<huffNode> greed;
21 //for the sake of convenience , assume that the
22 //standard input is from 'a' to 'z'.
23 int input(){
24 cout << "input the text!"<<endl;
25 cin >> buf;
26 for(int i = 0; i < 26 ; i++) count[i] = 0;
27 memset(huff , 0, sizeof(huff));
28 for(int i = 0; i < buf.length();i++)count[buf[i]-'a']++;
29 int len = 0;
30 for(int i = 0 ,j = 0; i < 26; i++)
31 if(count[i]){
32 huff[j].s = i + 'a';
33 huff[j].pow = count[i];
34 huff[j].pr = j;
35 cout << "the" << ' '<<'\''<< char(i+'a') <<'\''
36 <<' '<<"have arisen for " <<count[i]<<" time(s)"
37 <<endl;
38 greed.push(huff[j]);
39 len = j;
40 j++;
41 }
42 return len;
43 }
44
45 int createTree(int len){
46 if(len == 0) {
47 cout << " Only one kind of alf !"<<endl;
48 exit(1);
49 }
50 huffNode temp1 ,temp2,temp;
51 while(!greed.empty()){
52 temp1 = greed.top();
53 greed.pop();
54 temp2 = greed.top();
55 greed.pop();
56 len ++;
57 temp.lc = temp1.pr;
58 temp.rc = temp2.pr;
59 huff[temp1.pr].pr = huff[temp2.pr].pr = len;
60 temp.pr = len;
61 temp.pow = temp1.pow + temp2.pow;
62 huff[len] = temp;
63 if(!greed.empty()) greed.push(temp);
64 }
65 return len;
66 }
67
68 void reserve(char * a){
69 int len = strlen(a);
70 for(int i = 0 ; i <= len/2 ;i ++)
71 swap(a[i],a[len-i-1]);
72 }
73 struct code{
74 char s;
75 char co[50];
76 };
77
78 void coding(int len1,int len2){
79 code* mycode = new code[len1+1];
80 memset(mycode ,0 ,sizeof(mycode));
81 for(int i = 0; i <= len1 ; i++){
82 int j = i;
83 int t = 0;
84 mycode[i].s = huff[i].s;
85 while(j < len2){
86 if(huff[huff[j].pr].lc == j)
87 mycode[i].co[t++] = '0';
88 else mycode[i].co[t++] = '1';
89 j = huff[j].pr ;
90 }
91 reserve(mycode[i].co);
92 cout << "the code of " << mycode[i].s
93 << " is " << mycode[i].co <<endl;
94 }
95 delete[] mycode;
96 }
97
98 int main(){
99 int len1 = input();
100 int len2 = createTree(len1);
101 coding(len1,len2);
102 }
103
104
105
106