博文的記錄源自閱讀著名的酷殼主頁:
coolshell**並茂說明了這個問題——我們在刪除鍊錶的時候,常常需要記錄該結點在鍊錶中是否有前趨prev。如果有,那麼需要把prev->next指向該結點的next域,然後再刪除該結點,這樣才能保證鍊錶不會因為刪除結點而「斷開」。像這樣:
void remove(list_node **ref_head, list_node *del)那麼,在遍歷鍊錶的時候,這種方法需要對prev is null or not進行判斷,這在linus torvalds看來,是不聰明的做法,是不理解指標的表現。稍微想一下就知道,其實這樣做的根本原因也很明了,第一,需要知道被刪除的結點是否是鍊錶的頭結點,第二,需要保證鍊錶在刪除後不會「斷開」。else
delete cur;
cur =null;
break
; }
prev =cur;
cur = cur->next;}}
linus的做法是用乙個二級指標,去引用prev的next域。假設鍊錶的結構名為list_node,那麼這時要記錄的不是list_node *prev,而是list_node **ref_prev。首先,實現**是這樣的:
void remove(list_node **ref_head, list_node *del)由**可以看出,在執行cur = cur->next之前,首先用乙個二級指標去引用當前cur的next域,其實也就是引用了方法一中的prev->next,這個原理和函式中的「傳值」是一致的,就像swap函式一樣,如果函式原型如void swap(int a, int b),即pass-by-value,這時函式執行時的變數a,b只是傳入引數的乙個副本,函式執行完畢對傳入的變數值沒有影響,要讓值改變,函式應該是傳入位址void swap(int &a, int &b);**ref_prev的道理也是如此,它不是記錄prev,而是引用了prev的next域,在必要的時候改變prev->next的指向,這保證了鍊錶不「斷開」。其次,ref_prev的初始指向為鍊錶的頭結點,如果刪除的結點是頭結點,*ref_prev = cur->next也只是簡單地把頭結點改為原先頭結點的next結點,不需要再判斷prev是否為null了。ref_prev = &(cur->next);
cur = cur->next;}}
今天看到了一道題目,大體意思是鍊錶是排好序的,要你插入乙個結點後,仍保持排序。稍微想想,似乎也是需要記錄prev,如果插入的結點在鍊錶內(非頭結點也非尾結點),則要有這樣的操作:prev->next = new_node; new_node->next = cur; (這裡假定prev->value <= new_node->value <= cur->value, 即鍊錶是公升序排序的)很明顯,這裡的操作也可以用二級指標。
void insert_to_sorted_list(list_node **ref_head, int value, bool (*func)(int, int這裡考慮到題目未說明鍊錶的排序方式(公升序/降序),函式原型在引數裡加入了乙個函式指標。)) ref_next = &(cur->next);
cur = cur->next;
}*ref_next =new_node;
}
雙向鍊錶(二級指標實現)
include include typedef struct newlist onelist int insertone onelist old flist,onelist old elist,int a else else if q data a q next null else if q dat...
二級指標刪除單向鍊錶
給定乙個單鏈表,刪除該鍊錶中某些節點。乙個節點該不該刪除由函式remove 決定,該單鏈表刪除的函式原型為 struct listnode removeif struct listnode head,removefn remove 下面給出三種解法,主要是想突出第三種使用二級指標的方法。這個是我自己...
二級指標的使用
有時候,我們需要在函式體的內部申請記憶體空間並初始化,然後將內部申請的儲存空間交付給外部指標來引用,這時候,我們可以使用二級指標作為申請空間的函式的引數來實現。main.c檔案 include include include pragma pack push,1 typedef struct use...