Linked List 鍊錶詳解

2021-06-04 05:04:33 字數 4940 閱讀 1881

linked list basics

linked list problems

我覺得這兩篇講linked list的文章寫的非常非常好,所以在部落格裡自己寫一下,也算是溫習鞏固資料結構的知識了

本文結合乙個實際的例子來解釋什麼是linked list,如何使用linked list

不過在解釋linked list之前,必須先要了解指標的相關知識,這裡先做乙個簡單回顧一下指標

1.指標儲存了對另乙個變數的引用。 指標的值是乙個位址。

2.在c語言中,   *  這個符號被稱為解析符號,它用來取得指標所指向的那個變數的值,舉個例子

#includevoid main ()

上面這個例子在printf列印函式中,*p就是把指標p指向的變數a的值取出來

我記得我在學習c語言指標的時候,一直搞不清楚 * 這個符號,乙個原因就是 int* p=&a  在這行**中, int* p是申明了乙個指標,這一行**也能夠拆成兩行來寫

int *p;

p=&a;

但是請注意,int* p和 int *p這兩種寫法是一樣的,都是申明了乙個指向整形變數的指標,但是 int* p更好,因為 int* 表示這是乙個指向整形的指標,名字叫做p,而 int *p 的寫法容易讓人誤解為指標的名字叫做 *p,我當時學c語言時在這個問題上糾結了很久

3. & 這個符號叫做取位址符,在上面的例子中, int *p = &a; 這行**就是把變數 a 的位址賦給指標 p

關於指標內容其實非常多,這裡只是乙個簡單的回顧,想看更多關於指標的資料,我推薦大家看這篇文章,pointer and memory, 這篇文章是stanford大學的教授寫的,我看完以後,有一種豁然開朗的感覺

1. 陣列的長度是固定的。比如申明了乙個長度為100的整形陣列 int a[100], 陣列a的長度就是100,如果這時需要儲存200個數字,那麼a就用不了了

2. 陣列造成儲存空間的浪費。如果這時陣列a只儲存了 1個整數,那麼它的其他99個位置就相當於浪費了

3. 往陣列裡插入元素的開銷是非常大的。比如要在陣列的第乙個元素的位置上插入1個整數,那就得把陣列其他位置上的元素都向後移動一位

正因為陣列有以上的這些缺點,所以產生了linked list,linked list很好的克服了以上的三個缺點

首先,定義乙個名字叫做node的結構體

struct node ;

這個結構體中包含乙個整數,和乙個指向結構體node的指標

接下來我們寫乙個函式,生成乙個linked list

struct node* buildonetwothreefourfive()

現在,這個linked list就會有5個元素,如果列印出這個linked list的data值,那就是

求linked list長度的函式

int length(struct node* head) 

return count;

}

往這個linked list裡新增乙個節點,這個節點要在linked list的頭部,

void push(struct node** headref, int data)

這個push函式是乙個比較難理解的地方,因為它的引數列表有乙個引數 struct node** headref。

我們都知道, struct node* head表示的是乙個指向struct node的指標,名字是head

那麼,struct node** headref表示的就是乙個指向struct node的指標的指標,名字是headref

寫乙個函式,函式有兩個引數,乙個是linked list,另乙個是乙個整數,查詢在這個linked list裡有幾個元素的data值和整個整數相等

int length(struct node* head) 

return count;

}

取得linked list中的第n個元素的data值

int getnth(struct node* head, int index) 

assert(0);

}

刪除這個linked list

void deletelist(struct node** headref) 

*headref = null;

}

取出這個linked list裡頭部的那個節點的data值,並且銷毀第乙個節點

int pop(struct node** headref)

在第n個節點的位置上插入乙個節點

void insertnth(struct node** headref, int index, int data) 

assert(current != null);

push(&(current->next),data);

}}

假設乙個linked list已經按照data的公升序排列好了,這時往這個linked list新增乙個節點,這個節點會被加入的正確的位置上

void sortedinsert(struct node** headref, struct node* newnode) 

else

newnode->next = current->next;

current->next = newnode;

}}

linked list插入排序

void insertsort(struct node** headref) 

*headref = result;

}

把乙個鍊錶加入到另乙個鍊錶的尾部

struct node* current;

if(*aref == null)

else

*bref = null;

}把乙個鍊錶對半分,比如,鍊錶是, 分割後產生兩個鍊錶,第乙個, 第二個

void frontbacksplit(struct node* source, struct node** frontref, struct node** backref) 

else

}

去除鍊錶中的重複節點

void removeduplicates(struct node* head) 

else

}}

把第二個鍊錶的第乙個節點新增到第乙個鍊錶的頭節點上

void movenode(struct node** destref, struct node** sourceref)

alternatingsplit

每隔乙個節點取出的合成乙個linked list,比如,在 alternatingsplit()後生成兩個鍊錶   和

void alternatingsplit(struct node* source, struct node** aref, struct node** bref) 

*aref = a;

*bref = b;

}

shufflemerge

這個函式的目的需要舉例說明,比如,兩個鍊錶和,兩個鍊錶shufflemerge後的結構就是

也就是分別取出每個從每個煉表頭節點合併成乙個鍊錶

struct node* shufflemerge(struct node* a, struct node* b) 

}

sortedmerge

假設兩個鍊錶都是按照公升序遞增的,把兩個鍊錶合併,並且合併後的鍊錶也是按照公升序排列的

struct node* sortedmerge(struct node* a, struct node* b) 

else if (b == null)

if(a->data <= b->data)

else

tail = tail->next;

} return dummy.next;

}

mergesort

鍊錶的歸併排序

void mergesort(struct node** headref)

sortedintersect

假設兩個鍊錶是按照公升序排列的,找出兩個鍊錶相等的節點

struct node* sortedintersect(struct node* a, struct node* b) 

else if(a->data < b->data)

else

} return dummy.next;

}

reverse

鍊錶的倒置

這個是非遞迴版本

void reverse(struct node** headref) 

*headref = result;

}

下面這個是遞迴版本

void recursivereverse(struct node** headref)

倒置的操作比較複雜,需要畫圖去跟指標的變化

當然,我覺得最好的方法還是用gdb單步除錯,跟蹤指標變化

LinkedList 鍊錶

線性表是一種簡單的資料結構,其主要特點是元素之間存在 一對一 的關係,除去第乙個元素,每個元素都存在唯一乙個 前驅節點 除去最後乙個元素都存在唯一乙個 後繼節點 簡單的線性表有 陣列 單鏈表 雙向鍊錶 靜態鍊錶等。順序表 陣列 優缺點 陣列不僅邏輯上,物理上位置也相鄰,可隨機訪問,但刪除或插入元素時...

LinkedList 鍊錶

最近複習到鍊錶 linkedlist 一般來說共有大概有兩種實現方式 1.陣列實現 和 2.鏈式實現。我僅使用了直接鏈式實現,如下。其他的實現方式,大家不妨自己嘗試下吧。author ace yom peizhen zhang date 2015 8 17 description 鍊錶實現 ifnd...

鍊錶 LinkedList

原文中singlelinklist的remove方法有問題,因為是 node current firstnode.getnext 所以導致鍊錶的第乙個節點刪不掉。修改如下 public class singlelinklist 刪除某個節點 param element return 刪除成功返回tr...