[演算法淺析] 如何在O(1)的時間裡刪除單鏈表的結點,單鏈結點

來源:互聯網
上載者:User

[演算法淺析] 如何在O(1)的時間裡刪除單鏈表的結點,單鏈結點

題目是這樣的:給你一個單鏈表的表頭,再給你其中某個結點的指標,要你刪除這個結點,條件是你的程式必須在O(1)的時間內完成刪除。

由於有的同學對鏈表還不是很熟悉,本文盡量描述的通俗易懂,老鳥請直接跳過前面一大段。

鏈表結構如下:

struct node{    int val;    node* next;};

題目不是很難,很快就能想到好辦法:)

首先回顧一下普通的刪除方法,首先通過表頭,找到待刪除結點(設為B)的前一個結點(設為A),將A的指向改一下就行,然後刪除掉B結點就行了。要刪除的結點一定要delete掉,這不僅是個好習慣,而且能避免將來項目中可能造成的記憶體泄露的嚴重問題。

void DeleteNode_On(node *LinkList, node *p){    printf("delete:%d\n", p->val);    node *s = LinkList;    while(s->next != p)        s = s->next;    s->next = s->next->next;    delete(p);}

這個演算法主要耗時在於尋找前一個結點,所以是O(n)的演算法。

那麼既然要求是O(1),顯然不能再去for一遍了,聯想到數組的刪除,這個問題就比較好解決了。

首先我們很容易就能得到待刪除結點,即B結點的後一個結點C,然後將C的值賦值給B結點的值,相當於數組刪除時候的覆蓋,現在B結點和C結點一模一樣了,接下來就相當簡單了吧,我們不刪B,直接利用B刪掉C就行了,方法簡單,時間O(1)。


但是仔細想想這個演算法有個很明顯的缺陷,如果待刪除結點是最後一個結點呢?這個時候似乎沒有什麼好的解決辦法,只能老老實實的O(n)了。現在我們來看看平均時間複雜度:

符合題目要求。

void DeleteNode_O1(node *LinkList, node *p){    printf("delete:%d\n", p->val);    if(p->next != NULL) //如果p不是末尾結點, 則讓後一個結點覆蓋掉p, 然後刪除後一個結點    {        p->val = p->next->val;        node *tmp = p->next;        p->next = p->next->next;        delete(tmp);    }    else // 如果p是末尾結點, 則找到p的前一個結點然後正常刪除    {        node *s = LinkList;        while(s->next != p)            s = s->next;        s->next = s->next->next;        delete(p);    }}

最後附上完整測試代碼:

#include<iostream>using namespace std;struct node{    int val;    node* next;};void CreateLinkList(node *LinkList){    node *s = LinkList;    for(int i = 0; i < 10; i++)    {        node *t = new node;        t->val = i;        t->next = NULL;        s = s->next = t;    }}void ShowLinkList(node * LinkList){    node *s = LinkList->next;    while(s = s->next)        printf("%d ", s->val);    putchar(10);}void DeleteNode_On(node *LinkList, node *p){    printf("delete:%d\n", p->val);    node *s = LinkList;    while(s->next != p)        s = s->next;    s->next = s->next->next;    delete(p);}void DeleteNode_O1(node *LinkList, node *p){    printf("delete:%d\n", p->val);    if(p->next != NULL) //如果p不是末尾結點, 則讓後一個結點覆蓋掉p, 然後刪除後一個結點    {        p->val = p->next->val;        node *tmp = p->next;        p->next = p->next->next;        delete(tmp);    }    else // 如果p是末尾結點, 則找到p的前一個結點然後正常刪除    {        node *s = LinkList;        while(s->next != p)            s = s->next;        s->next = s->next->next;        delete(p);    }}int main(){    node *LinkList = new node;    CreateLinkList(LinkList);    ShowLinkList(LinkList);    node *p = LinkList->next;    for(int i = 0; i < 3; i++)        p = p->next;    DeleteNode_On(LinkList, p);    ShowLinkList(LinkList);    p = LinkList->next;    for(int i = 0; i < 8; i++)        p = p->next;    DeleteNode_O1(LinkList, p);    ShowLinkList(LinkList);    p = LinkList->next;    for(int i = 0; i < 4; i++)        p = p->next;    DeleteNode_O1(LinkList, p);    ShowLinkList(LinkList);    getchar();    return 0;}


設計一個在帶頭結點的單鏈表中刪除第i個結點的演算法

//刪除節點 刪除第i個節點
int Delete_Positon_LL(LinkList *phead,int i)
{
LinkList p,q;//p為值是x的節點,q是p的前一個節點
int j;

if((*phead)->next == NULL)//如果鏈表為空白,做下溢處理
{
printf("單鏈表為空白!\n");
return 0;
}
if(i == 1)//如果是表頭,表頭後移
{
p=(*phead)->next;
(*phead)->next=(*phead)->next->next;
free(p);//釋放表頭
}
else//從第二個節點尋找值是x的
{
q=(*phead)->next;
p=(*phead)->next->next;
j=2;
//注意先p !=NULL,否則將出現非法訪問操作
while(p !=NULL && j<i )
{
q=p;
p=p->next;
j++;
}

if(p!=NULL)//找到了
{
q->next=p->next;//讓前一個節點指向p的後繼節點
free(p);//刪除節點p
}
else
{
printf("刪除第%d個節點超出範圍.\n",i);
return 0;
}
}

return 1;

}
 
順序表、單鏈表的刪除演算法

單鏈表的刪除操作是指刪除第i個結點,返回被刪除結點的值。刪除操作也需要從頭引用開始遍曆單鏈表,直到找到第i個位置的結點。如果i為1,則要刪除第一個結點,則需要把該結點的直接後繼結點的地址賦給頭引用。對於其它結點,由於要刪除結點,所以在遍曆過程中需要儲存被遍曆到的結點的直接前驅,找到第i個結點後,把該結點的直接後繼作為該結點的直接前驅的直接後繼。刪除操作

單鏈表的刪除操作

刪除操作的演算法實現如下:
public T Delete(int i)
{
if (IsEmpty()|| i < 0)
{
Console.WriteLine("Link is empty or Position is error!");
return default(T);
}
Node q = new Node();
if (i == 1)
{
q = head;
head = head.Next;
return q.Data;
}
Node p = head;
int j = 1;
while (p.Next != null&& j < i)
{
++j;
q = p;
p = p.Next;
}
if (j == i)
{
q.Next = p.Next;
return p.Data;
}
else
{
Console.WriteLine("The ith node is not exist!");
return default(T);
}
}
演算法的時間複雜度分析:單鏈表上的刪除操作與插入操作一樣,時間主要消耗在結點的遍曆上。如果表為空白則不進行遍曆。當表非空時,刪除第i個位置的結點, i等於1遍曆的結點數最少(1個),i等於n遍曆的結點數最多(n個,n為單鏈表的長度),平均遍曆的結點數為n/2。所以,刪除操作的時間複雜度為O(n)。...餘下全文>>
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.