逆置單鏈表、替換法之無頭單鏈表的插入與刪除
1. 從尾到頭列印單鏈表
我們知道,單鏈表只能夠通過前面結點來找到後一個結點,不能直接通過後一個結點來找前一個結點,所以如何先列印後面的元素,在列印前面的元素。可以想到運用遞迴,設頭結點為first 第一次函式呼叫:first->next 第二次函式呼叫:first->next->next 第三次函式呼叫:first->next->next->next ······ ······ 依次下去,然後倒著輸出就可以了
void BackToFrontPrintRec(Node **ppfirst)
{
assert(ppfirst);
assert(*ppfirst );
Node *cur = *ppfirst;
if (cur == NULL)
{
return;
}
if (cur->next == NULL)
{
printf("%d ", cur->data);
return;
}
BackToFrontPrintRec(&cur->next);
printf("%d ", cur->data);
}
那麼不用遞迴又該如何輸出尼?我們可以使用last指標,第一次讓他指向NULL,第二次讓他指向倒數第一個結點,第三次讓他指向倒數第二個結點,依次類推,並將其數值列印即可
void BackToFrontPrint(Node **ppfirst)
{
assert(ppfirst);
assert(*ppfirst);
Node *last = NULL;
Node *cur = *ppfirst;
while (cur != last)
{
while (cur->next != last)
{
cur = cur->next;
}
printf("%d ", cur->data);
last = cur;
cur = *ppfirst;
}
}
2. 逆置單鏈表
我們很容易想到在建立一個連結串列進行操作,定義一個result指標為空(作為逆置後的尾結點的next),只需要讓原連結串列頭刪,然後在新連結串列頭插即可
void Reserve1(Node **ppfirst)
{
assert(ppfirst);
assert(*ppfirst);
Node *result = NULL;
Node *cur = *ppfirst;
Node *node = NULL;
while (cur != NULL)
{
//上面頭刪
node = cur;
cur = cur->next;
//下面頭插
node->next = result;
result = node;
}
}
第二種方法和第一種方法思想實際上是一樣的,但實現過程不一樣,p1指向要移動的結點,p2指向p1的下一個結點,p1實際就是上一中方法的result
void Reserve2(Node **ppfirst)
{
assert(ppfirst);
assert(*ppfirst);
Node *p1 = NULL;
Node *p2 = *ppfirst;
Node *p3 = p2->next;
while (p2 != NULL)
{
p2->next = p1;
p1 = p2;
p2 = p3;
if (p3 != NULL)
{
p3 = p3->next;
}
}
}
注:不管是哪種方法,都需要注意判斷條件,可以只照三個結點,按照上述步驟操作一下,就知道判斷條件怎樣設定比較好,當然,判斷條件不是唯一的
3. 刪除一個無頭單鏈表的非尾結點(不能遍歷連結串列)
我們只到,要刪除一個結點,我們可以從頭到尾找,然後刪除。但這個不知道頭結點,也就不能夠開始遍歷。這時候我們就要換一種思想——替換法,設要刪除的結點為node,我們可以把node->next->data放在node->data中,然後讓node指向node->next->next,這時候釋放的是node->next,而不是node。
void RemoveNoHeadNotTail(Node *node)
{
assert(node);
Node *next = node->next;
node->data = next->data;
node->next = next->next;
free(next);
}
4. 在無頭單鏈表的一個結點前面插入一個結點(不能遍歷)
這個和上一道題的思想是一樣的,我們無法找到node結點的前一個結點,只能講node和newNode裡面的資料進行交換,然後再將newNode插入即可(交換之後,就要將newNode插入到node的後面而不是前面了)
void InsertNoHeadNotTail(Node *node, DataType data)
{
assert(node);
Node *newNode = CreateNewNode(data);
newNode->data = node->data;
newNode->next = node->next;
node->data = data;
node->next = newNode;
}
注:替換法刪除不能刪除尾結點,替換法插入適用於任何結點。