日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

招商银行/招银网络科技面经、答案

發布時間:2023/12/31 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 招商银行/招银网络科技面经、答案 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、介紹一下static的各種用法,static修飾的變量在別的文件中可以使用嗎

Static修飾全局變量叫做靜態全局變量,

Static修飾局部變量叫做靜態局部變量,

Static修飾函數叫做靜態函數;

靜態全局變量:限制變量的作用域,僅在本文件中訪問,其他文件不可訪問;

靜態局部變量:僅在本函數體內訪問,本文件其他函數體內不可訪問;但靜態局部變量的值在程序運行期間不會銷毀;

靜態函數:僅在本文件中調用,其他文件中不可調用,即程序員不用擔心編寫的函數與其他文件的函數同名。
總的來說:
(1)在修飾變量的時候,static修飾的靜態局部變量只執行初始化一次,而且延長了局部變量的生命周期,直到程序運行結束以后才釋放。
(2)static修飾全局變量的時候,這個全局變量只能在本文件中訪問,不能在其它文件中訪問,即便是extern外部聲明也不可以。
(3)static修飾一個函數,則這個函數的只能在本文件中調用,不能被其他文件調用。Static修飾的變量存放在全局數據區的靜態變量區,包括全局靜態變量和局部靜態變量,都在全局數據區分配內存。初始化的時候自動初始化為0。
(4)不想被釋放的時候,可以使用static修飾。比如修飾函數中存放在棧空間的數組。如果不想讓這個數組在函數調用結束釋放可以使用static修飾。
(5)考慮到數據安全性(當程序想要使用全局變量的時候應該先考慮使用static)
2、static修飾類成員函數有什么作用
static修飾的函數叫做靜態函數,靜態函數有兩種,根據其出現的地方來分類:

如果這個靜態函數出現在類里,那么它是一個靜態成員函數;

靜態成員函數的作用在于:調用這個函數不會訪問或者修改任何對象(非static)數據成員。

其實很好理解,類的靜態成員(變量和方法)屬于類本身,在類加載的時候就會分配內存,可以通過類名直接去訪問;非靜態成員(變量和方法)屬于類的對象,所以只有在類的對象產生(創建類的實例)時才會分配內存,然后通過類的對象(實例)去訪問。
如果它不是出現在類中,那么它是一個普通的全局的靜態函數。

這樣的static函數與普通函數的區別是:**用static修飾的函數,限定在本源碼文件中,不能被本源碼文件以外的代碼文件調用。**而普通的函數,默認是extern的,也就是說它可以被其它代碼文件調用。

在函數的返回類型前加上關鍵字static,函數就被定義成為靜態函數。普通 函數的定義和聲明默認情況下是extern的,但靜態函數只是在聲明他的文件當中可見,不能被其他文件所用。因此定義靜態函數有以下好處:
 <1> 其他文件中可以定義相同名字的函數,不會發生沖突。
 <2> 靜態函數不能被其他文件所用。

3、const用法,const與define區別,const指針
C++ const 允許指定一個語義約束,編譯器會強制實施這個約束,允許程序員告訴編譯器某值是保持不變的。如果在編程中確實有某個值保持不變,就應該明確使用const,這樣可以獲得編譯器的幫助。
1、const與基本數據類型
int x = 3;//變量

const int x = 3;//常量

2、const修飾指針變量時:
  (1)只有一個const,如果const位于*左側,表示指針所指數據是常量,不能通過解引用修改該數據;指針本身是變量,可以指向其他的內存單元。

(2)只有一個const,如果const位于*右側,表示指針本身是常量,不能指向其他內存地址;指針所指的數據可以通過解引用修改。

(3)兩個const,*左右各一個,表示指針和指針所指數據都不能修改。
3、const與引用
int x = 3;

const int &y = x;

x = 10;//正確

y = 20;//錯誤,const修飾x的別名y,不能更改
例1:

const int x = 3;

int *y = &x; //erro

x是不可變的,但是我們定義的指針是可變的,可變的指針去指向一個不可變的變量,就會存在風險,會通過指針y來改變x的值;權限大的去接受權限小的,是不可行
二、const與#define的區別
(1) 編譯器處理方式不同
define宏是在預處理階段展開。
const常量是編譯運行階段使用。
(2) 類型和安全檢查不同
define宏沒有類型,不做任何類型檢查,僅僅是展開。
const常量有具體的類型,在編譯階段會執行類型檢查。
(3) 存儲方式不同
define宏僅僅是展開,有多少地方使用,就展開多少次,不會分配內存。(宏定義不分配內存,變量定義分配內存。)
const常量會在內存中分配(可以是堆中也可以是棧中)。

(4)const 可以節省空間,避免不必要的內存分配。 例如:
#define PI 3.14159 //常量宏
const doulbe Pi=3.14159; //此時并未將Pi放入ROM中 …
double i=Pi; //此時為Pi分配內存,以后不再分配!
double I=PI; //編譯期間進行宏替換,分配內存
double j=Pi; //沒有內存分配
double J=PI; //再進行宏替換,又一次分配內存!
const定義常量從匯編的角度來看,只是給出了對應的內存地址,而不是象#define一樣給出的是立即數,所以,const定義的常量在程序運行過程中只有一份拷貝(因為是全局的只讀變量,存在靜態區),而 #define定義的常量在內存中有若干個拷貝。
(5) 提高了效率。 編譯器通常不為普通const常量分配存儲空間,而是將它們保存在符號表中,這使得它成為一個編譯期間的常量,沒有了存儲與讀內存的操作,使得它的效率也很高。
(6) 宏替換只作替換,不做計算,不做表達式求解;
宏預編譯時就替換了,程序運行時,并不分配內存。

const 與 #define的比較
C++ 語言可以用const來定義常量,也可以用 #define來定義常量。但是前者比后者有更多的優點:
(1) const常量有數據類型,而宏常量沒有數據類型。編譯器可以對前者進行類型安全檢查。而對后者只進行字符替換,沒有類型安全檢查,并且在字符替換可能會產生意料不到的錯誤(邊際效應)。
(2) 有些集成化的調試工具可以對const常量進行調試,但是不能對宏常量進行調試。

4、指針和引用的區別
精簡版:

指針:變量,獨立,可變,可空,替身,無類型檢查;

引用:別名,依賴,不變,非空,本體,有類型檢查;

完整版:

  • 概念
  • 指針從本質上講是一個變量,變量的值是另一個變量的地址,指針在邏輯上是獨立的,它可以被改變的,包括指針變量的值(所指向的地址)和指針變量的值對應的內存中的數據(所指向地址中所存放的數據)。

    引用從本質上講是一個別名,是另一個變量的同義詞,它在邏輯上不是獨立的,它的存在具有依附性,所以引用必須在一開始就被初始化(先有這個變量,這個實物,這個實物才能有別名),而且其引用的對象在其整個生命周期中不能被改變,即自始至終只能依附于同一個變量(初始化的時候代表的是誰的別名,就一直是誰的別名,不能變)。
    (1)指針:指針是一個變量,只不過這個變量存儲的是一個地址,指向內存的一個存儲單元,即指針是一個實體;而引用跟原來的變量實質上是一個東西,只不過是原變量的一個別名而已。如:

    int a = 1; int *p = &a;
    int a = 1; int &b = a;
    1
    2
    上面定義了一個整型變量和一個指針變量p,該指針變量指向a的存儲單元,即p的值是a存儲單元的地址。

    而下面2句定義了一個整型變量a和這個整型a的引用b,事實上a和b是同一個東西,在內存占有同一個存儲單元。

    (2)可以有const指針,但是沒有const引用;
    (3)指針可以有多級,但是引用只能是一級(int **p;合法 而 int &&a是不合法的);
    (4)指針的值可以為空,但是引用的值不能為NULL,并且引用在定義的時候必須初始化;
    (5)指針的值在初始化后可以改變,即指向其它的存儲單元,而引用在進行初始化后就不會再改變了,從一而終。
    (6)sizeof引用得到的是所指向的變量(對象)的大小,而sizeof指針得到的是指針本身的大小;
    (7)指針和引用的自增(++)運算意義不一樣;

    二、相同點

    都是地址的概念;

    指針指向一塊內存,它的內容是所指內存的地址;

    引用是某塊內存的別名。
    5、什么情況會用到引用傳遞
    引用傳遞與值傳遞的區別就是:引用傳遞的時候,操作的是同一個對象,對現在的操作會改變原來的對象的值;而值傳遞的時候,操作的是原來對象的一個拷貝。對現對象的改變不會改變原來的對象的值
    C++中的指針參數傳遞和引用參數傳遞

    指針參數傳遞本質上是值傳遞,它所傳遞的是一個地址值。值傳遞過程中,被調函數的形式參數作為被調函數的局部變量處理,會在棧中開辟內存空間以存放由主調函數傳遞進來的實參值,從而形成了實參的一個副本(替身)。值傳遞的特點是,被調函數對形式參數的任何操作都是作為局部變量進行的,不會影響主調函數的實參變量的值(形參指針變了,實參指針不會變)。

    引用參數傳遞過程中,被調函數的形式參數也作為局部變量在棧中開辟了內存空間,但是這時存放的是由主調函數放進來的實參變量的地址。被調函數對形參(本體)的任何操作都被處理成間接尋址,即通過棧中存放的地址訪問主調函數中的實參變量(根據別名找到主調函數中的本體)。因此,被調函數對形參的任何操作都會影響主調函數中的實參變量。

    引用傳遞和指針傳遞是不同的,雖然他們都是在被調函數棧空間上的一個局部變量,但是任何對于引用參數的處理都會通過一個間接尋址的方式操作到主調函數中的相關變量。而對于指針傳遞的參數,如果改變被調函數中的指針地址,它將應用不到主調函數的相關變量。如果想通過指針參數傳遞來改變主調函數中的相關變量(地址),那就得使用指向指針的指針或者指針引用。

    從編譯的角度來講,程序在編譯時分別將指針和引用添加到符號表上,符號表中記錄的是變量名及變量所對應地址。指針變量在符號表上對應的地址值為指針變量的地址值,而引用在符號表上對應的地址值為引用對象的地址值(與實參名字不同,地址相同)。符號表生成之后就不會再改,因此指針可以改變其指向的對象(指針變量中的值可以改),而引用對象則不能修改。
    6、為什么在.h文件中使用#ifdef……
    ***這是一種防止頭文件被多次包含的預處理技術,***由于各種原因可能是有問題的。在編譯項目時,編譯每個.cpp文件(通常)。簡單來說,這意味著編譯器會把你的.cpp文件,打開任何文件#included,將它們全部連接成一個海量文本文件,然后執行語法分析,最后將它轉換成一些中間代碼,優化/執行其他任務,最后生成目標架構的匯編輸出。因此,如果#included一個.cpp文件下的文件多次,則編譯器將附加文件內容兩次,因此如果該文件中有定義,你會收到一個編譯器錯誤,告訴你重新定義了一個變量。FILE_H當編譯過程中的預處理器步驟處理文件時,首次到達其內容時,前兩行將檢查是否已為預處理器定義。如果沒有,它將定義FILE_H并繼續處理它和指令之間的代碼#endif。下一次該文件的內容被預處理器看到時,檢查FILE_H將是假的,所以它將立即掃描#endif并繼續。這樣可以防止重新定義錯誤。它將定義并繼續處理它和指令之間的代碼

    7、什么函數不能定義為虛函數
    常見的不能聲明為虛函數的有:普通函數(非成員函數);靜態成員函數;內聯成員函數;構造函數;友元函數。

    1.為什么C++不支持普通函數為虛函數?

    普通函數(非成員函數)只能被overload,不能被override,聲明為虛函數也沒有什么意思,因此編譯器會在編譯時邦定函數。

    2.為什么C++不支持構造函數為虛函數?

    這個原因很簡單,主要是從語義上考慮,所以不支持。因為構造函數本來就是為了明確初始化對象成員才產生的,然而virtual function主要是為了再不完全了解細節的情況下也能正確處理對象。另外,virtual函數是在不同類型的對象產生不同的動作,現在對象還沒有產生,如何使用virtual函數來完成你想完成的動作。(這不就是典型的悖論)

    3.為什么C++不支持內聯成員函數為虛函數?

    其實很簡單,那內聯函數就是為了在代碼中直接展開,減少函數調用花費的代價,虛函數是為了在繼承后對象能夠準確的執行自己的動作,這是不可能統一的。(再說了,inline函數在編譯時被展開,虛函數在運行時才能動態的邦定函數)

    4.為什么C++不支持靜態成員函數為虛函數?

    這也很簡單,靜態成員函數對于每個類來說只有一份代碼,所有的對象都共享這一份代碼,他不歸某個具體對象所有,所以他也沒有要動態邦定的必要性。

    5.為什么C++不支持友元函數為虛函數?

    因為C++不支持友元函數的繼承,對于沒有繼承特性的函數沒有虛函數的說法。
    8、智能指針作用及分類
    智能指針是一個類,這個類的構造函數中傳入一個普通指針,析構函數中釋放傳入的指針。智能指針的類都是棧上的對象,所以當函數(或程序)結束時會自動被釋放。

    作用
    C++程序設計中使用堆內存是非常頻繁的操作,堆內存的申請和釋放都由程序員自己管理。程序員自己管理堆內存可以提高了程序的效率,但是整體來說堆內存的管理是麻煩的,C++11中引入了智能指針的概念,方便管理堆內存。使用普通指針,容易造成堆內存泄露(忘記釋放),二次釋放,程序發生異常時內存泄露等問題等,使用智能指針能更好的管理堆內存。

    智能指針主要用于管理在堆上分配的內存,它將普通的指針封裝為一個棧對象。當棧對象的生存周期結束后,會在析構函數中釋放掉申請的內存,從而防止內存泄漏。
    分類:
    auto_ptr
    在 C++ 語言中,要使用 STL 中的 auto_ptr 對象,必須包含頭文件 memory,該文件包括 auto_ptr 模板。使用通常的模板句法來實例化所需類型的指針。auto_ptr 構造函數是顯式的,不存在從指針到 auto_ptr 對象的隱式類型轉換。
    auto_ptr(c++98的方案,c++11已經拋棄),采用的是所有權模式。
    模板可以通過構造函數將 auto_ptr 對象初始化為一個常規指針。auto_ptr 是一個智能指針,但其特性遠比指針要多。值得注意的是,在使用 auto_ptr 時,只能配對使用 new 和 delete。
    提示,只能對 new 分配的內存使用 auto_ptr 對象,不要對由 new() 分配的或通過聲明變量分配的內存使用它。

    unique_ptr
    unique_ptr實現獨占式擁有或者嚴格擁有概念,保證同一時間只有一個智能指針可以指向該對象。它對于避免資源泄露特別有用。

    shared_ptr
    shared_ptr實現共享式擁有概念。多個智能指針可以指向相同對象,該對象和其相關資源會在最后一個引用被銷毀時候釋放。通過use_count()來查看資源被幾個指針共享。除了可以通過new來構造,還可以通過傳入auto_ptr,unique_ptr,weak_ptr來構造。當我們調用release()時,當前指針會釋放資源所有權,計數減一。當計數等于0,資源會被釋放。
    成員函數:
    use_count()返回引用計數的個數;
    unique()返回是否獨占所有權;
    swap()交換兩個shared_pt6;
    reset()放棄內部對象的所有權或者擁有對象的變更,會引起原來對象的引用計數的減少;
    get()返回內部對象的地址。

    weak_ptr
    weak_ptr是用來解決shared_ptr相互引用時的死鎖問題,如果說兩個shared_ptr相互引用,那么這兩個指針的引用計數永遠不可能下降為0,資源永遠不會釋放。它是對對象的一種弱引用,不會增加對象的引用計數,和shared_ptr之間可以相互轉化,shared_ptr可以直接賦值給它,它可以通過調用lock函數來獲得shared_ptr。
    成員函數比shared_ptr多了兩個,但是少了get():
    expired() 為use_count()為0,返回true,否則返回false;
    lock()如果expired為空,返回空的shared_ptr;否則返回一個指向對象的shared_ptr;
    總結
    不要把一個原生指針給多個智能指針對象管理, 對所有的智能指針對象都成立。
    不要把 this 指針給智能指針對象,對所有的智能指針對象(包括 auto_ptr)都成立。
    不要在函數實參里創建智能指針對象。
    處理不是 new 創建的對象要小心. 如果確實需要這樣做, 需要智能指針傳遞一個刪除器, 自定義刪除行為。
    不要使用 new 創建一個智能指針對象.如 new shared_ptr 。
    使用 dynamic_pointer_cast 進行轉換。
    不要 memcpy 智能指針對象。
    智能指針對象數組的使用, 需要自定義釋放器。
    將智能指針對象作為函數參數傳遞時要小心, 如下面的代碼, 當調用所在的表達式結束(即函數調用返回)時, 這個臨時對象就被銷毀了, 它所指向的內存也被釋放.。
    當將一個智能指針對象(如 shared_ptr)綁定到一個普通指針時, 就將內存管理的責任交給了這個 shared_ptr. 此后就不應該使用內置指針來訪問 shared_ptr 所指向的內存了。
    不能使用 delete 釋放 get 返回的普通指針. get 函數的設計是為了向不能使用智能指針的代碼傳遞一個普通指針, 應該減少 get 函數的調用。
    不要使用 get 返回的普通指針來初始化另一個智能指針, 或為另一個智能指針賦值. 顯然如果這樣做, 將導致兩次釋放相同的內存, 或者其中一個已經將內存釋放, 但另一個還在使用。

    9、結構體與類、聯合體的區別
    首先一句話——在C++中,結構體和類沒有什么區別,唯一的區別就是:默認的訪問權限和繼承訪問權限不同。其他的,類能怎么干,結構體也能怎么干!

    默認訪問權限:結構體是public,類是private

    默認繼承訪問權限:結構體是public,類是private
    C++ primer 里面講,union是一種特殊的節省空間的類。

    一個union可以有多個數據成員,但是在任意時刻只能有一個數據成員有值。

    也就是說,當我們給某一個數據成員賦值之后,該union的其他數據成員就變成未定義的狀態了。

    分配給一個union的存儲空間至少要容納他的最大的數據成員。

    union與class類的區別:

    1、與結構體一樣,union的成員的默認訪問權限是public。

    2、union可以定義包括構造函數和析構函數在內的成員函數。

    3、既不能作為基類被繼承也不能繼承他人,union是獨立的,所以也不能實現虛函數。

    注意的點:

    1、union的數據成員可以是類類型, 但不能含有引用類型的成員,因為union的所有數據成員是要共享內存的。

    2、因為一旦給union的一個成員賦值的時候,其他的值就變成未定義的狀態啦,所以在使用union的時候必須知道當前union中存的是什么類型值。

    10、OSI七層協議
    我們都知道互聯網的本質是一系列的網絡協議,這個協議就叫做OSI(Open System Interconnect——開放式系統互聯的含義)協議。
    按照功能不同分工不同,人為的分為七層。實際上這七層是并不存在的,也就是說沒有這些概念,而我們今天提到的七層概念,只是人為的劃分而已。目的是為了讓我們更好地理解這些都是用來做什么的。
    物理層
    是參考模型的最底層。該層是網絡通信的數據傳輸介質,由連接不同結點的電纜與設備共同構成。
    主要功能是: 利用傳輸介質為數據鏈路層提供物理連接,負責處理數據傳輸并監控數據出錯率,以便數據流的透明傳輸。
    數據鏈路層
    是參考模型的第二層。
    主要功能是: 在物理層提供的服務基礎上,在通信的實體間建立數據鏈路連接,傳輸以"幀"為單位的數據包,并采用差錯控制與流量控制方法,使用差錯的物理線路變成無差錯的數據鏈路。
    網絡層
    是參考模型的第三層。
    主要功能是: 為數據在節點之間傳輸創建邏輯鏈路,通過路由選擇算法為分組通過通信子網選擇最適當的路徑,以及實現擁塞控制、網絡互連等功能。
    傳輸層
    是參考模型的第四層。
    主要功能是: 向用戶提供可靠地端到端服務,處理數據包錯誤、數據包次序,以及其他一些關鍵傳輸問題。傳輸層向高層屏蔽了下層數據通信的細節。因此,它是計算機通信體系結構中關鍵的一層。
    會話層
    是參考模型的第五層。
    主要功能是: 負責維護兩個結點之間的傳輸連接,以便確保點到點傳輸不中斷,以及管理數據交換等功能。
    表示層
    是參考模型的第六層
    主要功能: 用于處理在兩個通信系統中交換信息的表示方法,主要包括數據格式變換、數據加密與解密、數據壓縮與恢復等功能。
    應用層
    是參考模型的最高層。
    主要功能是: 為應用軟件提供了很多服務,比如文件服務器、數據庫服務、電子郵件與其他網絡軟件服務。

    11、三次握手
    三次握手(Three-way Handshake)其實就是指建立一個TCP連接時,需要客戶端和服務器總共發送3個包。進行三次握手的主要作用就是為了確認雙方的接收能力和發送能力是否正常、指定自己的初始化序列號為后面的可靠性傳送做準備。實質上其實就是連接服務器指定端口,建立TCP連接,并同步連接雙方的序列號和確認號,交換TCP窗口大小信息。

    剛開始客戶端處于 Closed 的狀態,服務端處于 Listen 狀態。
    進行三次握手:

    第一次握手:客戶端給服務端發一個 SYN 報文,并指明客戶端的初始化序列號 ISN。此時客戶端處于 SYN_SENT 狀態。

    首部的同步位SYN=1,初始序號seq=x,SYN=1的報文段不能攜帶數據,但要消耗掉一個序號。

    第二次握手:服務器收到客戶端的 SYN 報文之后,會以自己的 SYN 報文作為應答,并且也是指定了自己的初始化序列號 ISN(s)。同時會把客戶端的 ISN + 1 作為ACK 的值,表示自己已經收到了客戶端的 SYN,此時服務器處于 SYN_RCVD 的狀態。

    在確認報文段中SYN=1,ACK=1,確認號ack=x+1,初始序號seq=y。

    第三次握手:客戶端收到 SYN 報文之后,會發送一個 ACK 報文,當然,也是一樣把服務器的 ISN + 1 作為 ACK 的值,表示已經收到了服務端的 SYN 報文,此時客戶端處于 ESTABLISHED 狀態。服務器收到 ACK 報文之后,也處于 ESTABLISHED 狀態,此時,雙方已建立起了連接。

    確認報文段ACK=1,確認號ack=y+1,序號seq=x+1(初始為seq=x,第二個報文段所以要+1),ACK報文段可以攜帶數據,不攜帶數據則不消耗序號。

    發送第一個SYN的一端將執行主動打開(active open),接收這個SYN并發回下一個SYN的另一端執行被動打開(passive open)。

    12、進程與線程區別
    進程與線程的區別
    線程具有許多傳統進程所具有的特征,故又稱為輕型進程(Light—Weight Process)或進程元;而把傳統的進程稱為重型進程(Heavy—Weight Process),它相當于只有一個線程的任務。在引入了線程的操作系統中,通常一個進程都有若干個線程,至少包含一個線程。

    根本區別:進程是操作系統資源分配的基本單位,而線程是處理器任務調度和執行的基本單位

    資源開銷:每個進程都有獨立的代碼和數據空間(程序上下文),程序之間的切換會有較大的開銷;線程可以看做輕量級的進程,同一類線程共享代碼和數據空間,每個線程都有自己獨立的運行棧和程序計數器(PC),線程之間切換的開銷小。

    包含關系:如果一個進程內有多個線程,則執行過程不是一條線的,而是多條線(線程)共同完成的;線程是進程的一部分,所以線程也被稱為輕權進程或者輕量級進程。

    內存分配:同一進程的線程共享本進程的地址空間和資源,而進程之間的地址空間和資源是相互獨立的

    影響關系:一個進程崩潰后,在保護模式下不會對其他進程產生影響,但是一個線程崩潰整個進程都死掉。所以多進程要比多線程健壯。

    執行過程:每個獨立的進程有程序運行的入口、順序執行序列和程序出口。但是線程不能獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制,兩者均可并發執行

    13、判斷鏈表有環
    暴力法、哈希表、快慢指針
    14、平衡二叉樹定義
    如果在二叉查找樹中一開始給定的數列是有序的,那么在構建二叉查找樹時就會形成一條很長的鏈條式的樹,此時對這棵樹的查找復雜度將會變成O(n),起不到使用二叉查找樹來進行數據查詢優化的目的,于是需要對這顆樹的結構進行調整,使樹的高度在每次插入元素后仍然能保持O(logn)的級別,這樣能讓查詢的時間仍然是O(logn),于是就產生了平衡二叉樹。

    平衡二叉樹由前蘇聯兩位數學家提出,因此一般也稱為AVL樹,AVL樹仍然是一顆二叉查找樹,只是在其基礎上增加了“平衡”的要求。所謂平衡是指,對AVL樹的任意結點來說,其左子樹與右子樹的高度之差的絕對值不超過1,其中左子樹與右子樹的高度之差稱為該結點的平衡因子

    只要能隨時保證每個結點的平衡因子的絕對值不超過1, AVL的高度就始終能保持O(logn)級別,由于需要對每個結點都得到平衡因子,因此需要在樹的結構中加入一個變量height,用來記錄以當前結點為根結點的子樹的高度。

    15、用兩個棧實現一個隊列
    實現隊列

    template<typename T> class CQueue { public:CQueue(void);~CQueue(void);void appendTail(const T& node);T deleteHead();private:stack<T> stack1;stack<T> stack2; };template<typename T> void CQueue<T>::appendTail(const T& element)//尾插 {stack1.push(element); }template<typename T> T CQueue<T>::deleteHead() {if (stack2.size() <= 0){while (stack1.size > 0){T& data = stack1.top();stack1.pop();stack2.push(data);}}T head = stack2.top();stack2.pop();if (stack2.size() == 0)//當stack2為空時,拋異常throw new exception("queue is empty");return head; }

    總結

    以上是生活随笔為你收集整理的招商银行/招银网络科技面经、答案的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。