1.主旨
- 这是对于面试题6中的单向链表的前置实验,本人参照所学的《数据结构(C++语言版)》对双向链表进行了大概实现(单向链表即不使用前继或者后继)。所用的链表实现方式为头尾哨兵节点法,通过两个哨兵位置的恒定性,拓展出双向链的结构形式。
2.考点
- 考点1:链表实现时的基本节点ListNode的结构形式(value值,前继后继);
- 考点2:单向/双向链表的基本结构实现,如初始化与析构函数;
- 考点3:单向/双向链表的功能实现,比如插入函数、删除函数与查找函数等;
3.代码
3.1 基本的节点类
template<typename T> class ListNode
{
public:
T m_value;
ListNode<T>* m_pred;
ListNode<T>* m_succ;
};
3.2 双向链表类
- 特点:以模板类为基础,实现初始化、析构、秩查询、值查询、位置删除、值删除、首尾节点插入与前后节点插入这些基本功能,并进行了测试通过
- 问题:不过本代码具体的实现鲁棒性还是不够,对于各种越界的问题没有进行太妥善的处理,主要是为了便于理解以及面试时实现
template<typename T> class List
{
private:
int m_size;
ListNode<T>* m_header;
ListNode<T>* m_laster;
public:
List() { init(); }
int getSize() { return m_size; }
void init();
T& operator[] (int rank) const;
ListNode<T>* find(const T& value) const;
T erase(const T &value);
T erase(ListNode<T>* node);
ListNode<T>* insertAsPred(const T &value, ListNode<T>* node);
ListNode<T>* insertAsSucc(const T &value, ListNode<T>* node);
ListNode<T>* insertAsHead(const T &value);
ListNode<T>* insertAsLast(const T &value);
~List();
};
3.3 各个函数的实现过程
- 函数的实现过程基本都很易于理解,不易于理解的地方都写了注释
template<typename T> void List<T>::init()
{
m_header = new ListNode<T>;
m_laster = new ListNode<T>;
m_header->m_pred = NULL;
m_header->m_succ = m_laster;
m_laster->m_pred = m_header;
m_laster->m_succ = NULL;
m_size = 0;
}
template<typename T> T& List<T>::operator[](int rank) const
{
ListNode<T>* temp = m_header->m_succ;
while (rank--)
temp = temp->m_succ;
return temp->m_value;
}
template<typename T> ListNode<T>* List<T>::find(const T& value) const
{
ListNode<T>* temp = m_header->m_succ;
int size = m_size;
while (size--)
{
if (temp->m_value == value)
return temp;
temp = temp->m_succ;
}
return NULL;
}
template<typename T> T List<T>::erase(const T &value)
{
ListNode<T>* temp = find(value);
if (temp == NULL)
return NULL;
T temp_value = temp->m_value;
temp->m_succ->m_pred = temp->m_pred;
temp->m_pred->m_succ = temp->m_succ;
delete temp;
m_size--;
return temp_value;
}
template<typename T> T List<T>::erase(ListNode<T>* node)
{
if (node == NULL)
return NULL;
T node_value = node->m_value;
node->m_succ->m_pred = node->m_pred;
node->m_pred->m_succ = node->m_succ;
delete node;
m_size--;
return node_value;
}
template<typename T> ListNode<T>* List<T>::insertAsPred(const T &value, ListNode<T>* node)
{
if (node == NULL)
return NULL;
ListNode<T>* temp = new ListNode<T>;
temp->m_value = value;
node->m_pred->m_succ = temp;
temp->m_pred = node->m_pred;
node->m_pred = temp;
temp->m_succ = node;
m_size++;
return temp;
}
template<typename T> ListNode<T>* List<T>::insertAsSucc(const T &value, ListNode<T>* node)
{
if (node == NULL)
return NULL;
ListNode<T>* temp = new ListNode<T>;
temp->m_value = value;
node->m_succ->m_pred = temp;
temp->m_succ = node->m_succ;
node->m_succ = temp;
temp->m_pred = node;
m_size++;
return temp;
}
template<typename T> ListNode<T>* List<T>::insertAsHead(const T &value)
{
ListNode<T>* temp = new ListNode<T>;
temp->m_value = value;
m_header->m_succ->m_pred = temp;
temp->m_succ = m_header->m_succ;
m_header->m_succ = temp;
temp->m_pred = m_header;
m_size++;
return temp;
}
template<typename T> ListNode<T>* List<T>::insertAsLast(const T &value)
{
ListNode<T>* temp = new ListNode<T>;
temp->m_value = value;
m_laster->m_pred->m_succ = temp;
temp->m_pred = m_laster->m_pred;
m_laster->m_pred = temp;
temp->m_succ = m_laster;
m_size++;
return temp;
}
template<typename T> List<T>::~List()
{
while (m_size)
erase(m_header->m_succ);
delete m_laster;
delete m_header;
}
3.4 测试用主函数与运行结果
int main()
{
List<int> test;
for (int i = 0; i < 10; i++)
{
test.insertAsHead(i);
test.insertAsLast(i);
}
cout << "test[5]:" << test[5] << endl;
cout << "test[15]:" << test[15] << endl;
cout << "test.find(8)->m_value:" << test.find(8)->m_value << endl;
cout << "test.erase(test.find(4)):" << test.erase(test.find(4)) << endl;
cout << "test.erase(8)->m_value:" << test.erase(8) << endl;
cout << "test.insertAsPred(11, test.find(8))->m_value:" << test.insertAsPred(11, test.find(8))->m_value << endl;
cout << "test.insertAsSucc(13, test.find(5))->m_value:" << test.insertAsSucc(13, test.find(5))->m_value << endl;
int size = test.getSize();
for (int i = 0; i < size; i++)
cout << test[i] << " ";
cout << endl;
return 0;
}