1.用遞歸算法,刪除帶結點的單鏈表L中所有值爲x的結點。
由於是帶頭結點的,所以並且查找值爲x的結點時,從L->next的值開始判斷,
如果L->next的data等於x,那麼就要將L->next的值刪除並且將L的後繼結點換成L->next的後繼結點,並且將它刪除。
LNode *P = L->next ;
L->next=L->next->next;
free(P)
遞歸模型:
終止條件:
L->next == NULL
遞歸主體:
如果L->next->data= = x:
刪除L->next結點,並執行L->next=L->next->next操作,繼續執行下一個結點值判斷。
如果L->next != x:
直接判斷下一個結點。
LNode* delectList(LNode*L, int x)
{
if (L->next== NULL)
return L;
else
{
if (L->next->data==x)
{
LNode *P = L->next;
L ->next= L->next->next;
free(P);
delectList(L, x);
}
else
{
delectList(L->next, x);
}
}
}
2.在頭結點的單鏈表,編寫算法實現從尾到頭反向輸出每個結點的值。
第一種:
反向輸出,可以頭結點的後繼結點開始,直到L->next=NULL,用頭插法的方式將後面的結點插在頭結點後面,然後在依次打印。
第二種:
棧是一種後進先出的結構,遞歸就是用棧的思想實現的。
void R_Print(LNode *L){
if (L->next != NULL)
{
R_Print(L->next);//遞歸
}
cout << L->data << endl;
}
3.將帶頭結點的鏈表就地逆置(就地要求輔助空間複雜度爲O(1))。
其實這幾道題的思想都差不多,這道題就是將頭結點取下然後將後續結點用頭插法的方式插入,直到最後一個結點。
LNode* Reverse_L(LNode *L)
{
LNode *move = L->next;//移動指針,頭結點後的一個結點開始
L->next = NULL;
LNode *r;
while (move != NULL)
{
r = move->next;//存放帶插入的結點
move->next = L->next;//頭插法的方式
L->next = move;
move = r;//移動工作結點
}
return L;
}
4.將帶頭結點的鏈表刪除最小值結點的高效算法(最小結點唯一)
思路:
第一步尋找最小值
第二步將最小值刪除
在尋找最小值時用需要從頭到尾一次比較,將最小值的前驅用指針保存。
刪除時只需要將前驅的後繼結點指向改變即可。
空間複雜度爲O(1),時間複雜度爲O(n)
LNode* deletemin(LNode *L)
{
LNode *move = L->next;//移動的工作結點
LNode *min = L;//保存最小值前驅的結點
while (move->next != NULL)
{
if (min->next->data > move->next->data)
{
min = move;
}
move = move->next;
}
LNode *s = min->next;//要刪除的結點
min->next = min->next->next;//前驅結點的後繼結點改變
free(s);
return L;
}
全部代碼:
/*
Instruction:Linklist insertion
author:huangpingyi
date:2017/02/23
*/
#include <iostream>
using namespace std;
struct LNode
{
int data;
LNode *next;
};
//尾插法
LNode* CreateListT(LNode *L, int x, int array[])
{
L->next = NULL;
LNode *q = L;
LNode *s;//插入的結點
int i = 0;
while (i < x)
{
s = new LNode;
s->data = array[i];
//以下三步是尾插法和頭插法的區別
L->next = s;
s->next = NULL;
L = s;
i++;
}
return q;
}
//遞歸刪除值爲x的結點
LNode* delectList(LNode*L, int x)
{
if (L->next== NULL)
return L;
else
{
if (L->next->data==x)
{
LNode *P = L->next;
L ->next= L->next->next;
free(P);
delectList(L, x);
}
else
{
delectList(L->next, x);
}
}
}
//從頭到尾反向輸出結點
void R_Print(LNode *L){
if (L->next != NULL)
{
R_Print(L->next);//遞歸
}
cout << L->data << endl;
}
//就地逆置鏈表
LNode* Reverse_L(LNode *L)
{
LNode *move = L->next;//移動指針,頭結點後的一個結點開始
L->next = NULL;
LNode *r;
while (move != NULL)
{
r = move->next;//存放帶插入的結點
move->next = L->next;//頭插法的方式
L->next = move;
move = r;//移動工作結點
}
return L;
}
//刪除鏈表中最小值結點
LNode* deletemin(LNode *L)
{
LNode *move = L->next;//移動的工作結點
LNode *min = L;//保存最小值前驅的結點
while (move->next != NULL)
{
if (min->next->data > move->next->data)
{
min = move;
}
move = move->next;
}
LNode *s = min->next;//要刪除的結點
min->next = min->next->next;//前驅結點的後繼結點改變
free(s);
return L;
}
//打印結果
void Print(LNode *L)
{
L = L->next;//第一個是頭結點
while (L != NULL)
{
cout << L->data << endl;
L = L->next;
}
}
int main(){
int x, array[10];
cout << "請輸入插入個數:" << endl;
cin >> x;
cout << "輸入需要插入的數據:" << endl;
for (int i = 0; i < x; i++)
{
cin >> array[i];
}
LNode* L = new LNode;
CreateListT(L, x, array);//d調用後爲啥L不變
cout << "用尾插法創建鏈表的結果:" << endl;
Print(L);
int delect;
cout << "請輸入需要刪除的數" << endl;
cin >> delect;
delectList(L, delect);
cout << "用遞歸法刪除x後結果" << endl;
Print(L);
cout << "從頭到尾反向輸出結果" << endl;
R_Print(L->next);
cout << "此時鏈表的順序" << endl;
Print(L);
Reverse_L(L);
cout << "就地逆置後的結果:" << endl;
Print(L);
cout << "刪除結點的最小值結果" << endl;
deletemin(L);
Print(L);
system("pause");
return 0;
}
運行效果: