练习--实现双向链表

1.题目(算法p103-p104):

实现一个双向链表,并且实现以下的函数:

(1)在指定的节点之前插入节点

(2)在指定的节点之后插入节点

(3)删除指定节点

(4)removeAfter(),接受一个链表节点作为参数,并删除该节点的后续节点

(5)find(),接受一个key值,如果链表中某个节点的data域的值跟key相等,那么就返回true,否则返回false


2.分析:双向链表存在着两个指针域,一个指向前面的节点,一个指向后面的节点,相对于单链表来说,双向链表的好处有:

i.便于删除节点,双向链表因为保存着上一个节点的地址,所以我们进行删除操作的时候所编写的代码会易读很多。

ii.插入和删除操作相对较少。


3.实现:

#ifndef LIST_HPP
#define LIST_HPP

#include <iostream>
using namespace std;


//定义节点类
template <typename T>
class Node
{
public:
	Node(T item) : next(NULL), pre(NULL), data(item){}
	~Node(){}
	Node* next;
	Node* pre;
	T data;
};

//链表
template <typename T>
class MyList
{
public:
	MyList();
	~MyList();
	void insertBefore(Node<T>* position, T data);   //在指定节点之前插入节点
	void insertAfter(Node<T>* position, T data);	//在指定节点之后插入节点
	void insert(T data);							//在表尾插入节点
	void deleteNode(Node<T>* position);				//删除指定节点
	void removeAfter(Node<T>* position);			//删除指定节点之后的所有节点
	bool isEmpty();									//判空
	void printList();								//打印链表
	bool find(T data);								//找到指定数据的节点
	Node<T>* at(int count);							//找到位于链表第count个的节点
	Node<T>* getFirst() {return first;}				//头指针
	Node<T>* getTail() {return tail;}				//尾指针
private:
	Node<T>* first;
	Node<T>* tail;
	int size;
};

template <typename T>
MyList<T>::MyList() : first(NULL),tail(NULL), size(0){}

template <typename T>
MyList<T>::~MyList(){}

template <typename T>
void MyList<T>::insertBefore(Node<T>* position, T data)
{
	if (position == NULL && !isEmpty())		//如果position 为空,且链表有数据的话,结束函数
	{
		return ;
	}

	if (isEmpty())		//如果链表为空,那么就新建一个节点
	{
		Node<T>* currentNode = new Node<T>(data);
		first = tail = currentNode;
	}
	else if (position->pre == NULL)		//如果在表头进行插入节点,那么就把新插入的节点当做头节点
	{
		Node<T>* currentNode = new Node<T>(data);
		currentNode->next = position;
		position->pre = currentNode;
		first = currentNode;
	}
	else	//如果在两个节点之间插入节点
	{
		Node<T>* currentNode = new Node<T>(data);
		Node<T>* preNode = position->pre;
		preNode->next = currentNode;
		currentNode->pre = preNode;
		currentNode->next = position;
		position->pre = currentNode;
	}
	size++;
}

template <typename T>
void MyList<T>::insertAfter(Node<T>* position, T data)
{
	if (position == NULL && !isEmpty()) //如果position 为空,且链表有数据的话,结束函数
	{
		return ;
	}

	if (isEmpty())   //如果链表为空,那么就新建一个节点
	{
		Node<T>* currentNode = new Node<T>(data);
		first = tail = currentNode;
	}
	else if (position->next == NULL) //如果在表尾进行插入节点,那么就把新插入的节点当做尾节点
	{
		Node<T>* currentNode = new Node<T>(data);
		currentNode->pre = position;
		position->next = currentNode;
		tail = currentNode;
	}
	else    //如果在两个节点之间插入节点
	{
		Node<T>* currentNode = new Node<T>(data);
		Node<T>* nextNode = position->next;
		nextNode->pre = currentNode;
		currentNode->pre = position;
		currentNode->next = nextNode;
		position->next = currentNode;
	}
	size++;
}

//在表尾进行插入操作
template <typename T>
void MyList<T>::insert(T data)
{
	if (isEmpty())
	{
		Node<T>* currentNode = new Node<T>(data);
		first = tail = currentNode;
	}
	else
	{
		Node<T>* currentNode = new Node<T>(data);
		tail->next = currentNode;
		currentNode->pre = tail;
		tail = currentNode;
	}
	size++;
}

//删除指定的节点
template <typename T>
void MyList<T>::deleteNode(Node<T>* position)
{
	if (isEmpty() || position == NULL)	//如果传入参数不正确或者链表为空的话,结束调用
	{
		return ;
	}
	
	if (position == first)			//如果是删除头节点
	{
		Node<T>* currentDelete = first;
		first = first->next;
		currentDelete->next = NULL;
		delete currentDelete;
	}
	else if (position == tail)		//如果是删除尾节点
	{
		Node<T>* currentDelete = tail;
		tail = tail->pre;
		currentDelete->pre = NULL;
		delete currentDelete;
	}
	else	//如果是删除中间节点
	{
		Node<T>* nextNode = position->next;
		Node<T>* preNode = position->pre;
		position->next = NULL;
		position->pre = NULL;
		nextNode->pre = preNode;
		preNode->next = nextNode;
		delete position;
	}
	size--;
}

//删除指定节点后面的所有节点
template <typename T>
void MyList<T>::removeAfter(Node<T>* position)
{
	int number = 0;
	Node<T>* currentNode = position->next;
	position->next = NULL;
	while (currentNode != NULL)
	{
		Node<T>* deleteNode = currentNode;
		currentNode = currentNode->next;
		delete deleteNode;
		number++;
	}
	size -= number;
}

//打印链表
template <typename T>
void MyList<T>::printList()
{
	if (size == 0)
	{
		cout << "List is empty !" << endl;
		return ;
	}
	Node<T>* currentNode = first;
	while(currentNode != NULL)
	{
		cout << currentNode->data << " ";
		currentNode = currentNode->next;
	}
	cout << endl;
}

//找到指定的节点,找到返回true,找不到返回false
template <typename T>
bool MyList<T>::find(T data)
{
	Node<T>* currentNode = first;
	bool result = false;
	while (currentNode != NULL)
	{
		if (currentNode->data == data)
		{
			result = true;
			break;
		}
	}
	return result;
}

//找到位于链表中count的节点,并返回指向节点的指针
template <typename T>
Node<T>* MyList<T>::at(int count)
{
	if (count > size)
	{
		return NULL;
	}
	Node<T>* currentNode = first;
	int num = 1;
	while (num++ != count)
	{
		currentNode = currentNode->next;
	}
	return currentNode;
}

//判空
template <typename T>
bool MyList<T>::isEmpty()
{
	return size == 0;
}

#endif


主函数就不贴出来了,上面的函数经过测试,都能正常使用,代码风格不好,有待加强。


4.再一次写了链表,从大二到现在已经写了很多次链表了,但是每一次重新写都要在纸上写写画画很多才能写出来,而且可能有很多的细节没有考虑进去,但是比起大二,还是强了那么一点点,用笔和纸来帮助自己构造链表是最好不过的。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值