資料結構-單鏈表的讀取,插入與刪除
連結串列定義:
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;
}