C++使用單向迴圈連結串列解決
需要實現節點的插入和刪除
——我為++做實事
1 、節點定義:
struct node
{
int number; // 表示序號
node *next;
};
2 、節點的插入:
為每個節點(人)發放生死序號:index
考慮連結串列為空和不為空的情況
void insert_Node(node *&head, int index)
{
node *newNode = new node;
// 如果連結串列為空
if (head == nullptr)
{
newNode->number = index;
newNode->next = newNode; // next指標指向自己
head = newNode; // 把自己設為頭節點
}
else
{
newNode->number = index;
newNode->next = head; // next指標指向頭節點
node *N = find_tail(head);
N->next = newNode; // 尾節點的next指向自己
}
}
3 、刪除節點的操作:
當我們刪除連結串列中的節點時,一般只需要修改附近節點的 next 指標即可,不過此題使用了 new 來分配空間,所以還需要 delete 掉節點,防止記憶體洩漏。如果用陣列模擬連結串列就不用考慮真的“刪除”節點這個問題。
3 .1 有以下幾種情況:
如果是頭節點
是否有且只有頭節點
除了頭節點還有其他節點
如果不是頭節點
3.2 需要注意釋放記憶體
delete node
程式碼:
void del_Node(node *&head, node *victim)
{
if (victim == head) // 如果刪除的是頭節點
{
node *tail = find_tail(head);
if (head == tail) // 連結串列只有一個節點
{
delete head; // 釋放記憶體
head = nullptr; // 設定為空
}
else // 除了頭節點還有其他節點
{
head = head->next; // 修改頭節點
tail->next = head; // 尾節點指向新的頭節點
delete victim; // 釋放記憶體
}
}
else // 刪的不是頭節點
{
node *before_victim = head;
while (before_victim->next != victim)
before_victim = before_victim->next;
before_victim->next = victim->next; // 刪除 victim,修改前面節點的next指標
delete victim; // 釋放記憶體
}
}
4. Main 函式
一定要初始化頭節點為空,作為連結串列的一個標誌
程式碼邏輯:
為 30 個人發號碼牌
迴圈 15 次,每次丟出去一個人(好殘忍)
每次從當前的人這裡,往前走 8 步,找到 victim
刪除 victim
指標移動到這個 victim 下一位,下次迴圈就從這人開始,繼續走 8 步……
程式碼:
int main()
{
node *head = nullptr; // 一定要初始化頭節點為空
for (int i = 1; i <= 30; i++)
insert_Node(head, i);
int all_people = 30, half_people = all_people / 2;
node *victim = head;
while (half_people--)
{
for (int i = 0; i < 8; i++)
victim = victim->next;
cout << victim->number << " ";
node *next_vic = victim->next;
del_Node(head, victim);
victim = next_vic;
cout << endl;
// print(head);
}
return 0;
}
最後是些無關緊要的輔助函式
1、find_tail 函式
// 返回連結串列最後一個節點的指標
node *find_tail(node *head)
{
node *N = head;
while (N->next != head) // find尾節點
{
N = N->next;
}
return N;
}
2、列印連結串列函式(debug 用可刪)
// 列印當前剩下的所有人
void print(node *head)
{
node *c = head;
if (c == nullptr)
return; // 空連結串列處理
do
{
cout << c->number << " ";
c = c->next;
} while (c != head); // 列印直到頭節點
cout << endl;
}
小韓碎碎念 —有些 bug 值得注意:
1、對於連結串列的修改,包括插入和刪除,傳進函式一定要用 &
,引用傳遞,否則只會在函式內部修改,不會對原始連結串列有任何影響。
2、關於 while 和 do-while 的一個 bug:
原始碼:
void print(node * head)
{
node *c = head;
while(c->next != head)
cout << c->number << " ";
}
問題:
print
函式的邏輯問題: print
函式缺少列印連結串列最後一個節點的程式碼,因為它只迴圈到 c->next != head
,而沒有列印尾節點。因此,你會錯過列印最後一個節點
改成 do-while 迴圈後的程式碼:
void print(node * head)
{
node *c = head;
if (c == nullptr)
return; // 空連結串列處理
do
{
cout << c->number << " ";
c = c->next;
} while (c != head); // 列印直到頭節點
cout << endl;
}