1. 程式人生 > >資料結構-單鏈表的讀取,插入與刪除

資料結構-單鏈表的讀取,插入與刪除

連結串列定義:

struct ListNode
{
  int value;
  ListNode *next;
};

單鏈表讀取

在順序儲存結構中,比如陣列中,想要獲取某一個位置的資料是非常容易的一件事,但是在連結串列中卻要麻煩一些,因為連結串列的儲存單元並不是連續的,而且我們只知道連結串列的頭結點,也就是想知道第i個位置的資料,只能從頭找下去,並沒有什麼其他的好方法。
需要注意的是,如果i大於連結串列的長度的話程式會異常,所以需要加上判斷。

#include<iostream>
using namespace std;

struct ListNode
{
int
value; ListNode *next; }; ListNode* GetElem(ListNode * L,int i); void CreateList(ListNode * L,int n); int main() { ListNode * L = new ListNode; L->next = nullptr; CreateList(L,5); ListNode* elem = GetElem(L,3); if (elem==nullptr) { cout<<"error"<<endl; } else
{ cout<<elem->value<<endl; } getchar(); getchar(); return 0; } void CreateList(ListNode * L,int n) { cin>>L->value;//輸入第一個結點的資料值 n--; for (int i = 0; i < n; i++) { ListNode * p = new ListNode; cin>>p->value; p->next = nullptr
; L->next = p; L = p; } } ListNode* GetElem(ListNode * L,int i) { int j; ListNode *p=L; j =1; while (p && j<i) { p = p->next; j++; } if (!p || j>i) { return nullptr; } return p; }

在上面的程式碼中,傳入GetElem函式的是連結串列的頭結點,這個程式碼和《大話資料結構》這本書裡面的例程有些不同,如果有人也碰巧看那本書的話,可以留意一下。

單鏈表插入

相比於順序儲存結構,連結串列的讀取確實麻煩了些,但是好在插入和刪除方便。比如要在連結串列的第三個結點之後插入一個結點。
這裡寫圖片描述
這裡的1-6只是結點裡面存的資料,不決定結點的順序。
(1)找到連結串列中第三個結點p
(2)建立一個新的結點q ListNode *q=(ListNode*)malloc(sizeof(ListNode));q->value=4;
(3)q先與原連結串列第四個結點連結q->next = p->next;
(4)原連結串列第三個結點與q連結p->next = q;
(3和4的順序不能對調,所以圖示就是這樣)
這裡寫圖片描述
我們假設一下,如果3,4對調了,也就是說先讓第三個結點指向q,因為我們是可以在原連結串列上找到第三個結點的,但是一旦指向發生了變化,原連結串列斷了,原連結串列的第四個結點就已經找不到了。但是不對調的話,在原連結串列沒有斷開之前就把q與第四個結點連起來了,又由於本來我們就找到了原連結串列的第三個結點,所以即便斷開了,那又能怎麼樣呢??

#include<iostream>
using namespace std;

struct ListNode
{
int value;
ListNode *next;
};
void showList(ListNode * L);
ListNode* ListInsert(ListNode * L,int i);
void CreateList(ListNode * L,int n);
int main()
{
    ListNode * L = new ListNode;
    L->next = nullptr;
    CreateList(L,5);
    ListNode* Head = ListInsert(L,3);
    showList(Head);
    getchar();
    getchar();
    return 0;
}
void CreateList(ListNode * L,int n)
{
    cin>>L->value;//輸入第一個結點的資料值
    n--;
    for (int i = 0; i < n; i++)
    {
        ListNode * p = new ListNode;
        cin>>p->value;
        p->next = nullptr;
        L->next = p;
        L = p;
    }
}
ListNode* ListInsert(ListNode * L,int i)
{
    int j;

    ListNode *p=L;
    j =1;
    while (p && j<i)
    {
        p = p->next;
        j++;
    }
    if (!p || j>i)
    {
        return nullptr;
    }

    ListNode *q=(ListNode*)malloc(sizeof(ListNode));

    q->value=4;
    //3
    q->next = p->next;
    //4
    p->next = q; 

    return L;
}
void showList(ListNode * L)
{
    ListNode * p = L;
    while (p)
    {
        cout<<p->value<<' ';
        p = p->next;
    }
    cout<<endl;
}

這裡寫圖片描述

單鏈表刪除

要刪除一個連結串列中第三個結點後面的結點,邏輯與插入操作很類似,同樣要考慮原連結串列斷開後的情況:
這裡寫圖片描述
步驟是這樣:
(1)找到第三個結點p
(2)找到p後面的結點q(在圖中是第四個)q= p->next;
(3)將p指向q後面的結點(在圖中是第五個)p->next = q->next;
(4)釋放qfree(q);
這裡寫圖片描述

#include<iostream>
using namespace std;

struct ListNode
{
int value;
ListNode *next;
};
void showList(ListNode * L);
ListNode* ListDelete(ListNode * L,int i);
void CreateList(ListNode * L,int n);
int main()
{
    ListNode * L = new ListNode;
    L->next = nullptr;
    CreateList(L,5);
    ListNode* Head = ListDelete(L,3);
    showList(Head);
    getchar();
    getchar();
    return 0;
}
void CreateList(ListNode * L,int n)
{
    cin>>L->value;//輸入第一個結點的資料值
    n--;
    for (int i = 0; i < n; i++)
    {
        ListNode * p = new ListNode;
        cin>>p->value;
        p->next = nullptr;
        L->next = p;
        L = p;
    }
}
ListNode* ListDelete(ListNode * L,int i)
{
    int j;
    ListNode *q;
    ListNode *p=L;
    j =1;
    while (p && j<i)
    {
        p = p->next;
        j++;
    }
    if (!p || j>i)
    {
        return nullptr;
    }

    //3
    q= p->next;
    //4
    p->next = q->next; 
    free(q);
    return L;
}
void showList(ListNode * L)
{
    ListNode * p = L;
    while (p)
    {
        cout<<p->value<<' ';
        p = p->next;
    }
    cout<<endl;
}

這裡寫圖片描述