链表(二)双向链表

一.链表节点

1.链表节点的定义

#include<iostream>
#include<algorithm>
using namespace std;
class LinkNode
{
public:
	int Data;
	LinkNode* Prev;
	LinkNode* Next;
	LinkNode(int data);
	LinkNode();

};

2.链表节点的实现

将新节点的next指针和prev指针设为null

#include "LinkNode.h"

LinkNode::LinkNode(int data)
	:Data(data),Prev(nullptr),Next(nullptr)
{
}

LinkNode::LinkNode()
	:Prev(nullptr),Next(nullptr)
{
}

二.双链表实现

1.链表接口

#include<iostream>
#include<algorithm>
#include"LinkNode.h"
using namespace std;
class LinkList
{
private:
	LinkNode* Head;//头节点
	LinkNode* Curr;//当前节点
	LinkNode* Tail;//尾节点
	int Size;
public:
	LinkList();
	bool isEmpty();//判空
	void BuildListByHeadInsert(int ele);//头插法建表
	void BuildListByTailInsert(int ele);//尾插法建表同时在尾节点处插入节点
	void BackwardInsert(int ele);//	在当前节点(位于中间)的后一个节点插入一个新节点
	void ForwardInsert(int ele);//	在当前节点(位于中间)的前一个节点插入一个新节点
	void BackwardInsertByNode(int ele, LinkNode* Node);//在已知节点(位于中间)的后一个节点插入一个新节点
	void ForwardInsertByNode(int ele, LinkNode* Node);//在已知节点(位于中间)的前一个节点插入一个新节点
	int getSize();//获取表长
	void Delete();//删除当前节点的下一个节点
	void DeleteByNode(LinkNode* Node);//删除已知节点的下一个节点
	int getCurr();//获取当前节点的数据
	void SequentialPrint();//顺序打印链表
	void ReversePrint();//序打印链表
	LinkNode* GetHead();//获取头节点
	void Prev();//将当前节点后移一位
	int Find(int ele);//按值查找节点
	int At(int pos);//按位置查找节点
	void Clear();//清空链表内元素但不删除
	void Destory();//销毁链表
	LinkNode* GetElemByPos(int pos);//按位置查找节点
	LinkNode* GetElemByValue(int ele);//按值查找节点
	void setTail();//设置尾节点
	int CaculateSize();//计算链表长
	int getTail();
};

2.初始化

1.创建一个新节点设为头节点

2.将尾节点设为头节点

LinkList::LinkList()
	:Size(0)
{
	Head = new LinkNode;
	Curr = Head;
	Tail = Head;
}

3.建表操作

Ⅰ.头插法

 每次将节点插入到链表的表头的前一个节点,生成的节点次序和输入数据相反

一.若头节点后无节点 新节点和头节点双向联系

1.将头节点的next和新节点相连

2.将新节点的prev和头节点联系

二.若头节点后有节点 新节点和头节点后驱双向联系

1.新节点的next指向头节点的后驱

2.头节点后驱的prev指向新节点

新节点和头节点双向联系 ​

1.将头节点的next和新节点相连 ​

2.将新节点的prev和头节点联系

三.若新节点的下一个节点为空节点则将新节点设为尾节点

时间复杂度:O(N)

void LinkList::BuildListByHeadInsert(int ele)
{
	Size++;
	LinkNode* Temp = new LinkNode(ele);
	if (Head->Next == NULL)
	{
		//新节点和头节点建立双向联系
		Temp->Prev = Head;
		Head->Next = Temp;
	}
	else
	{
		//新节点和头节点的后驱建立双向联系
		Head->Next->Prev = Temp;//将当前节点的后一个节点的上一个节点设为新节点
		Temp->Next = Head->Next;//将新节点的后驱节点为当前节点的后驱节点
		//新节点和头节点建立双向联系
		Temp->Prev = Head;
		Head->Next = Temp;
	}
	//setTail();
	if (Temp->Next == nullptr)
	{
		Tail = Temp;
	}
}

Ⅱ.尾插法

每次将节点插入到链表的表头的后一个节点,生成的节点次序和输入数据相同

1.将新节点和尾节点双向联系

将尾节点的next和新节点相连

将新节点的prev和尾节点联系

2.将新节点设为尾节点

3.将尾节点的下一个节点设为空节点

void LinkList::BuildListByTailInsert(int ele)
{
	Size++;
	LinkNode* Temp = new LinkNode(ele);
	//和尾节点建立双向联系
	if (Tail->Next == nullptr)
	{
		Tail->Next = Temp;
		Temp->Prev = Tail;
	}
	Tail = Temp;
}

4.插入操作

Ⅰ.后插法

一.和插入位置的后驱节点建立双向联系

1.将新节点的next为插入位置的next相连

2.将插入位置的next的prev和新节点相连

二.和插入位置建立双向联系

1..将新节点的prev设为插入位置

2.将插入位置的next设为新节点

三.若新节点的下一节点为空则设新节点为尾节点

void LinkList::BackwardInsertByNode(int ele, LinkNode* Node)
{
	Size++;
	LinkNode* Temp = new LinkNode(ele);
	//和当前节点的后一个节点建立双向联系
	Temp->Next = Node->Next;//将新节点的后驱节点为当前节点的后驱节点
	Node->Next->Prev = Temp;//将当前节点的后一个节点的上一个节点设为新节点
	//和当前节点建立双向联系
	Temp->Prev = Node;//将新节点的上一个节点设为当前节点
	Node->Next = Temp;//将当前节点的后驱节点设为新节点
	if (Temp->Next == nullptr)Tail = Temp;
}

Ⅱ.前插法

在后插法的基础上交换元素

void LinkList::ForwardInsertByNode(int ele, LinkNode* Node)
{
	Size++;
	LinkNode* Temp = new LinkNode(ele);
	//和当前节点的后一个节点建立双向联系
	Temp->Next = Node->Next;//将新节点的后驱节点为当前节点的后驱节点
	Node->Next->Prev = Temp;//将当前节点的后一个节点的上一个节点设为新节点
	//和当前节点建立双向联系
	Temp->Prev = Node;//将新节点的上一个节点设为当前节点
	Node->Next = Temp;//将当前节点的后驱节点设为新节点
	swap(Temp->Data, Node->Data);
}

5.删除操作

一.设被删除节点为删除位置的后驱节点

二.将删除位置和被删除节点的后驱节点相连

1.删除位置的next和被删除节点的后驱节点相连

2.被删除节点的后驱节点的prev指向删除位置

三.将节点删除

四.若删除位置的后一个节点为空,将删除位置设置为尾节点

void LinkList::DeleteByNode(LinkNode* Node)
{
	Size--;
	LinkNode* Temp = Node->Next;//被删除节点
	//和被删除的后驱节点进行双向关联
	Node->Next = Temp->Next;
	Temp->Next->Prev = Node;
	delete Temp;
	if (Node->Next == NULL)Tail = Node;
}

6.查找操作

1.按值查找

LinkNode* LinkList::GetElemByValue(int ele)
{
	LinkNode* Temp = Head->Next;
	while (Temp)
	{
		if (Temp->Data == ele)
		{
			return Temp;
		}
		Temp = Temp->Next;
	}
}

2.按位置查找

LinkNode* LinkList::GetElemByPos(int pos)
{
	LinkNode* Temp = Head;
	for (int i = 1; i <= pos; i++)
	{
		Temp = Temp->Next;
	}
	return Temp;
}

7.其他操作

1.判空

bool LinkList::isEmpty()
{
	//return Size==0;
	return Head->Next == nullptr;
}

2.清空链表

1.头节点的下一节点视为数组下标为1

2.遍历链表,但循环中要保存要删除节点中的后驱节点

3.移动节点

4.将头节点的下一节点设为空指针

void LinkList::Clear()
{
	if (Head->Next == nullptr)//若为空表
		return;
	else
	{
		LinkNode* Temp = Head->Next;//头节点的下一节点视为数组下标为1
		while (Temp != nullptr)
		{
			LinkNode* Temp_Next = Temp->Next;//保存要删除节点的后驱节点
			delete Temp;//删除节点
			Temp = Temp_Next;//移动被删除节点
		}
		Head->Next = nullptr;//
		Size = 0;
	}
}

3.销毁链表

1.判断是否为空表

2.清空链表

3.删除头节点,将头节点设为空节点

void LinkList::Destory()
{
	if (Head->Next == nullptr)//若为空表
	{
		return;
	}
	else
	{
		this->Clear();
		delete Head;
		Head = nullptr;
		cout << "Successful Destory" << endl;
	}
}

4.计算链表长

int LinkList::CaculateSize()
{
	int length = 0;
	LinkNode* Temp = Head->Next;
	while (Temp)
	{
		length++;
		Temp = Temp->Next;
	}
	return length;
}

5.遍历输出链表

1.顺序输出
void LinkList::SequentialPrint()
{
	if (Head->Next == nullptr)
	{
		cout << "空链表" << endl;
	}
	int i = 1;
	LinkNode* Temp = Head->Next;
	while (Temp)
	{
		cout << "节点" << i << "为:" << Temp->Data << endl;
		Temp = Temp->Next;
		i++;
	}
}
2.逆序输出
void LinkList::ReversePrint()
{
	if (Head->Next == nullptr)
	{
		cout << "空链表" << endl;
	}
	int i = 0;
	LinkNode* Temp = Tail;
	while (Temp->Prev)
	{
		cout << "节点" << Size-i << "为:" << Temp->Data << endl;
		Temp = Temp->Prev;
		i++;
	}
}

三.测试函数

#include"LinkList.h"
#include<iostream>
#include<random>
using namespace std;
int main()
{
	LinkList Test;
	cout << (Test.isEmpty() ? "Test表为空" : "Test表不为空") << endl;
	int time;
	cout << "输入元素个数为:";
	cin >> time;
	random_device rd;
	mt19937 gen(rd());
	uniform_int_distribution<> dis(1, 10);
	for (int i = 0; i < time; i++)
	{
		int ele;
		ele = dis(gen);
		Test.BuildListByHeadInsert(ele);
	}
	Test.SequentialPrint();
	cout << endl;
	Test.ReversePrint();
	cout << endl;
	cout << Test.getTail() << endl;
	LinkNode* Temp = Test.GetElemByPos(4);
	Test.BackwardInsertByNode(10, Temp);
	Test.SequentialPrint();
	cout << Test.getTail() << endl;
	

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值