算法進行時--單鏈表(二)常見題型01

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;
}

運行效果:




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章