链表中的指针
中期答辯改在了國慶之后,終于有時間可以看看劍指offer了。在看到單向鏈表的部分,對指針,尤其是頭指針有點疑惑。首先容易理解的是鏈表的節點是一個結構體,該結構體包含一個數據(一般是int型),還包含一個指向該結構體類型的指針。通過指針的指向一個個遍歷,也是通過指針一次次分配內存。這使得鏈表不同于數組,鏈表中的內存不是連續的,我們想要訪問一個結點只能從頭結點開始。其實數組之所以能通過數組下標進行訪問,也是因為事先設定了一個基準點。只不過在鏈表中這個基準點(頭指針)很重要。現在就來好好研究一下頭指針、頭結點的那些事。
?
在書中提供的代碼中,無論是在鏈表末尾插入新的結點,還是在鏈表中刪除具有某值的結點,都有兩個共同點。一是函數的第一個參數類型是指向結點數據類型的指針的指針,一是將代碼分為兩部分,第一部分都是通過頭指針是否是空指針判斷該鏈表是否是空鏈表,或者判斷頭結點中的數據是否和參數相等。這里提到了兩個重要的概念,頭指針和頭結點。
struct ListNode {int value;ListNode * Next;};void addTotail(ListNode ** head, int value){//第一個參數是頭指針的指針,因為頭指針在變ListNode* newlistnode = new ListNode();newlistnode->value = value;newlistnode->Next = NULL;//新建一個節點,數據等于參數,指針為空if (*head == NULL){//頭指針,指向下一個節點*head = newlistnode;//空鏈表中插入節點,則頭指針不再是空指針,第一個形參應改變}else {//鏈表不空時,遞歸直到鏈表尾(空指針)ListNode* pNode = *head;while (pNode->Next != NULL){pNode = pNode->Next;}pNode->Next = newlistnode;} }可以看到空指針相對于數組名,是鏈表的名字,它是指向下一個結點的指針的指針,至于為什么是雙重指針,這涉及到函數中參數值的傳遞。因為在鏈表中插入我們要討論該鏈表是否是空鏈表,進行不同的操作,而插入這個操作會使得空鏈表不再空,即使得原來空鏈表的頭指針指向空指針變成了指向一個真實的結構體,我們需要在執行完一次函數后修改頭指針這個形參,方便之后再次調用這個函數。
函數中值的傳遞方式有三種:值傳遞,地址傳遞,引用傳遞。
值傳遞,只傳遞了形參的值,因為在函數內部會新建值等于參數的副本(形參),函數中的操作只是對副本進行修改,不會改變實參的原始大小。實參是主函數調用函數時傳遞的值,形參是函數定義時使用的值。一個很形象的例子就是餐廳中有保鮮膜包好的樣品菜,你指給廚師說要菜A,廚師會拿新的食材重新做一份,而不是直接把樣品給你。如果真的想要樣品中的菜,那么就要借助裝樣品的盤子了,盤子就相當于地址,這就是地址傳遞。Java中只有按值傳遞,這也是java簡單的原因。
引用傳遞。首先搞清楚引用是怎么回事,引用是兩個變量名表示同一個東西,不會分配新的內存,可以認為引用是目標變量的一個別名。通過引用修改變量勢必引起原始變量發生變化。
下面說一下今天遇到的主角,指針傳遞。這里更特殊的是使用了雙重指針。這里有一句比較容易引起混淆的話:其實一切傳遞的方式本質都是按值傳遞。簡單來說,雙重指針通過傳遞地址變量和地址指針指向的內容實現了可以通過函數對參數的地址和內容值進行修改。
先看下面一個代碼,代碼中第一個參數是指向int型的指針,傳入a的地址。可以理解為&a是按值傳遞的,這樣在執行函數時會有一個a的地址的拷貝,這個拷貝同樣指向a,這樣當我們在函數中修改拷貝中的內容,即便這個拷貝最后被釋放,還是會改變a的值。
void change(int *_a,int &b){ *_a=b; } void main(){ int a=10,b=20; int *p_a=&a; change(p_a,b); printf("%d",*p_a); }既然單指針作為形參已經可以實現通過函數修改實參,為什么還要使用雙重函數呢?可以注意到我們剛才把a的地址當做按值傳遞,而函數目標是修改按值傳遞的地址指向的內容,但是當我們函數的目的是修改地址本身時,又回到了按值傳遞的老路上,這樣是不能實現目的的。借鑒剛才的通過指針改變指針指向的內容,我們再加一層指針,指向變量的地址,即指針的指針,這就有了雙重指針。
再說回頭指針和頭結點。頭指針是必要的,頭結點更多是為了操作統計和方便,其數據域一般無意義,可以用作監視哨或者存放鏈表的長度。代碼中,只要頭指針運用了next操作就自動創建了頭結點。再從表示的意義理解一下雙重指針ListNode ** pHead,它是指向結構體ListNode的指針的指針,那么*pHead表示的就是指向ListNode的一個指針。
Reference:
總結
- 上一篇: 检测系列--RCNN系列
- 下一篇: C++继承一览