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