Q: 不同數據結構的優缺點?
數據結構
優點
缺點
數組(Array)
快速訪問,如果知道下標,就可以非常快地存取
查找慢, 插入或刪除慢, 大小固定
有序數組(OrderedArray)
比無序的數組查找快
插入或刪除慢,大小固定
棧(Stack)
提供后進先出方式的存取
存取其他項很慢
隊列(Queue)
提供先進先出方式的存取
存取其他項很慢
鏈表(LinkedList)
插入快,刪除快
查找慢
二叉樹(BinaryTree)
查找、插入、刪除都快(如果樹保持平衡)
刪除算法復雜
紅-黑樹(RBTree)
查找、插入、刪除都快。樹總是平衡的
算法復雜
2-3-4樹(2-3-4Tree)
查找、插入、刪除都快。樹總是平衡的。類似的樹對磁盤存儲有用
算法復雜
哈希表(HashTable)
如果關鍵字已知則存取極快。插入快
刪除慢,如果不知道關鍵字則存取很慢,對存儲空間使用不充分
堆(Heap)
插入、刪除快,對最大數據項的存取很快
對其他數據項存取慢
圖(Graph)
對現實世界建模
有些算法慢且復雜
Q: 算法的概述?
A:許多算法直接適用於上面的數據結構,都需要知道如何:
1) 插入一個新的數據項
2) 刪除某一特定的數據項
3) 尋找某一個特定的數據項
4) 如何迭代地訪問各個數據項
5) 排序
Q: 為什么面向對象編程比面向過程編程要好一些?
A:面向過程編程,如C、Pascal或早期版本的Basic在處理大型的復雜問題時有些力不從心,為什么會這樣呢?有兩類問題:一是程序與現實世界缺乏相應關系;二是程序內部的結構出現了問題。
A:對現實世界建模的無能為力
使用過程語言對現實世界問題進行抽象及概念化十分困難:方法執行任務,而數據存儲信息,但是現實世界中的事物是對兩者同時進行操作的。
例如,爐子上的自動調溫器例子,如果用過程語言來寫這個程序,可能會以兩個函數turnOn()和turnOff()即爐開和爐閉來完成,但是還會有兩個全局變量currentTemp和desiredTemp,即現在的溫度和希望的溫度。
然而這些函數和變量並沒有形成任何編程對象,在程序中不會出現任何可以稱之為自動調溫器的單元,這個單元的唯一概念僅存在程序員的腦海中。
對於大型的程序,有可能包括上百個類似調溫器的實體,面向過程語言對這種情況將會使程序變得極為混亂,錯誤頻繁出現,有時甚至不可能實現方案,因此需要一種可以更好地將程序中的事物與現實中的事物相匹配的語言。
A:粗糙的組織結構
解決程序的內部組織是一個更微妙而且事關重大的問題。面向對象被划分為一個一個的函數,這種基於函數組織形式的一個巨大問題是它僅僅考慮了函數,而沒有重視數據。當不得不面對數據時,它沒有過多的選擇。簡而言之,數據可以是一個特定的函數的局部變量,也可以使所有函數都可以存取的全局變量,就是無法規定一個變量只允許某些函數存取而不允許另一些函數存取。
如果一個變量要想被多個函數存取到,就必須為全局變量,但是全局變量會在不經意間被程序的任何一個函數存取,這就導致了頻繁的程序錯誤。
Q: 什么是軟件工程?
A:軟件工程研究是許多程序員參與的大型復雜的計算機程序的創建方法。它強調是程序的整體設計和如何依照最終用戶需求而進行設計的問題。
A:軟件工程關系一個軟件項目的整個生命周期,包括分析、設計、驗證、編碼、測試、生產和維護各個階段。
Q: C++和Java的幾處不同?
A:這里只列出可以幫助C++程序員看懂示例的Java特性
A:沒有指針
Java和C++的最大區別在於Java沒有指針,其實,Java只是擺脫了顯示表露的指針,指針依舊是以存儲地址的形式隱藏在程序的深處,有時甚至可以說在Java中,所有的東西都是指針。
1) 引用(reference)
Java對基本數據類型的處理與對象的處理不同
int nVar; // an int variable called nVar
BankAccount bankAccount; // reference to a BankAccount object
在第一行語句中,一個被稱為nVar的存儲地址保存了一個數值127,然而,bankAccount這個存儲地址並沒有保存BankAccount對象的數據,這個名稱bankAccount是對象的引用,它並不是對象本身。
實際上,如果bankAccount沒有被預先賦值的話,它就不會稱為引用。在賦值為某個對象之前,它保存了一個被稱為null的特殊對象的引用。同樣,nVar在它被賦值之前也不會保存數值。如果嘗試使用一個被賦值的變量,編譯器會報錯。
在C++中
BankAccount bankAccount;
實際上在棧里創建了一個對象,它留出了所有這個對象的數據的空間。而在Java中,這條語句只創建了一個放置某一對象的存儲地址的空間。可以將Java引用認為是普通變量語法中的指針。
2) 賦值
Java中的賦值操作符與C++中的不一樣。
在C++中,這條語句:
bankAccount2 = bankAccount1;
將一個名為bankAccount1的對象的所有數據都拷貝到另一個名為bankAccount2的對象中。然而在Java中,這條語句的賦值語是向bankAccount2拷貝了bankAccount1指向的存儲地址,現在bankAccount1和bankAccount2實際指的是同一個對象,它們都是這個對象的引用。
如果對賦值操作符理解不深的話,上面的語句會讓人感到困惑。
如果想對一個對象中復制數據到另一個對象中,必須保證在一開始就有兩個不同的對象,然后分別拷貝每個字段,等號是不起復制的作用的。
3) new操作符
在Java中任何創建對象的工作必須使用new。但是new在Java中返回一個引用,而不像C++中返回一個指針。下面是創建對象的一個方法:
BankAccount bankAccount = null;
bankAccount = new BankAccount();
取消指針意味着一個更安全的系統。程序員不可能找到bankAccount的真實地址,也就不可能意外地破壞它。
用new向堆申請空間后,如何去釋放那些不再使用的空間?在C++中,可以使用delete。在Java中,則根本不需要對釋放空間擔心。Java每隔一段時間就會查看每一塊由new開辟的內存,看指向它的有效引用是否依舊存在,如果這個引用不存在,系統會自動將這塊空間歸入空閑內存區。這個過程被稱為垃圾回收。
幾乎所有的程序員在使用C++過程中都會有忘記刪除存儲空間的經歷,這會導致“內存泄漏”(memory leak)從而消耗系統資源,使程序處於不穩定的狀態,甚至會導致系統崩潰。內存泄漏在Java中不可能出現(或至少幾乎沒有)。
4) 參數
在C++中,指針經常被用來在函數間傳遞對象,從而避免拷貝一個大對象的系統開銷。在Java中,對象經常以引用的形式傳遞,這種方法同樣地避免了對象的拷貝:
void f1() {
BankAccount bankAccount = new BankAccount(270.00);
f2(bankAccount);
}
void f2(BankAccount ba) {}
上面的代碼中引用bankAccount和ba都指向同一個對象,而在C++中,ba則是從bankAccount拷貝而來的另一個對象。
然而,簡單的基本數據類型總是通過它的值來傳遞。
5) 相等與同一
在Java中,對基本數據類型,可以通過相等操作符(==)來判斷兩個變量是否含有相同的值:
int a = 12;
int b = a;
if (a == b) {
System.out.println("they are equal");
}
這同C/C++語法。
但是在Java中,由於關系操作符使用引用,所以它們在涉及到對象的判斷時有些不同。 當使用相等操作符(==)判斷類時,實際上判斷的是類的引用是否一致,即它們是否指向的是同一個對象:
BankAccount ba1 = new BankAccount(250.00);
BankAccount ba2 = ba1;
if (ba1 == ba2) {
System.out.println("they are identical");
}
在C++中,這個操作符會判斷兩個對象是否含有相同的數據。如果在Java中要判斷兩個對象是否含有相同的數據,則使用Object類的equals()方法:
BankAccount ba1 = new BankAccount(250.00);
BankAccount ba2 = new BankAccount(250.00);
if (ba1 == ba2) {
System.out.println("they are equal");
}
A:重載操作符
Java中沒有重載操作符,在C++中可以重新定義+、*、=及大多數其他操作符,以便使它們在特定的類中達到不同的效果。在Java中,任何類似的重新定義都是不可能的,而可以使用命名的方法,如add()或其他名字。
A:基本數據類型
Java八種基本數據類型
參考
《Java數據結構和算法》Robert Lafore 著,第1章 - 綜述