目标
使用Linux内核链表实现双向循环链表DualCircleList。
设计思路
数据结点之间在逻辑上构成双向循环链表,头结点仅用于结点的定位。
实现思路
(1)通过模板定义 DualCirclelist 类,继承自 DualLinkList类;
(2)在 DualCircleList 内部使用 Linux 内核链表进行实现;
(3)使用 struct list_head 定义 DualCirclelist 的头结点;
(4)特殊处理:循环遍历时忽略头结点。
实现要点
(1)通过list_head进行目标结点的定位(position(i));
(2)通过list_entry将list_head指针转换为目标结点指针;
(3)通过list_for_each实现int find(const T& e)函数;
(4)遍历函数中的next()和pre()需要考虑跳过头结点。
代码实现
#ifndef _DUALCIRCLELIST_
#define _DUALCIRCLELIST_
#include "LinuxList.h"
#include "DualLinkList.h"
namespace DTLib
{
template <typename T>
class DualCircleList : public DualLinkList<T>
{
protected:
struct Node : public Object
{
list_head head;
T value;
};
list_head m_header;
list_head* m_current;
list_head* position(int i) const
{
list_head* ret = const_cast<list_head*>(&m_header); // position函数为const
for (int p = 0; p < i; p++)
{
ret = ret->next;
}
return ret;
}
int mod(int i) const
{
return (this->m_length == 0) ? 0 : (i % this->m_length);
}
public:
DualCircleList()
{
this->m_length = 0;
this->m_step = 1;
m_current = NULL;
INIT_LIST_HEAD(&m_header);
}
bool insert(const T& e)
{
return insert(this->m_length, e);
}
bool insert(int i, const T& e)
{
bool ret = true;
Node* node = new Node();
i = i % (this->m_length + 1);
if (node != NULL)
{
node->value = e;
list_add_tail(&node->head, position(i)->next);
this->m_length++;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No memory to insert new element...");
}
return ret;
}
bool remove(int i)
{
bool ret = true;
i = mod(i);
ret = ((0 <= i) && (i < this->m_length));
if (ret)
{
list_head* toDel = position(i)->next;
if (m_current == toDel)
{
m_current = m_current->next;
}
list_del(toDel);
this->m_length--;
// delete toDel; // 因为toDel实际上指向的是节点中的head成员,要将它转换为真正的节点!
// delete的时候是list_head,但是new出来的是Node
// list_entry不仅调整了指针的位置也调整的指针所指的大小(list_entry不仅仅是调整位置,因为
// delete的时候不仅需要内存位置也需要知道内存的大小)
delete list_entry(toDel, Node, head);
}
return ret;
}
bool set(int i, const T& e)
{
bool ret = true;
i = mod(i);
ret = ((0 <= i) && (i < this->m_length));
if (ret)
{
// position(i)->next->value = e;错
// 应该将position(i)->next这个指针转换成指向实际节点的指针
list_entry(position(i)->next, Node, head);
}
return ret;
}
T get(int i) const
{
T ret;
if (get(i, ret))
{
return ret;
}
else
{
THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element...");
}
return ret;
}
bool get(int i, T& e) const
{
bool ret = true;
i = mod(i);
ret = ((0 <= i) && (i < this->m_length));
if (ret)
{
// e = position(i)->next->value;错,原因同bool set(int i, const T& e)
e = list_entry(position(i)->next, Node, head)->value;
}
return ret;
}
int find(const T& e) const
{
int ret = -1;
int i = 0;
list_head* slider = NULL;
list_for_each(slider, &m_header)
{
if (list_entry(slider, Node, head)->value == e)
{
ret = i;
break;
}
i++;
}
return ret;
}
int length() const
{
return this->m_length;
}
void clear()
{
while (this->m_length > 0)
{
remove(0);
}
}
bool move(int i, int step = 1)
{
bool ret = (step > 0);
i = mod(i);
ret = ret && ((0 <= i) && (i < this->m_length));
if (ret)
{
m_current = position(i)->next;
this->m_step = step;
}
return ret;
}
bool end()
{
return (m_current == NULL) || (this->m_length == 0);
}
T current()
{
if (!end())
{
return list_entry(m_current, Node, head)->value;
}
else
{
THROW_EXCEPTION(InvalidOperationException, "No value at current position...");
}
}
bool next() // 要跳过头结点
{
int i = 0;
while ((i < this->m_step) && !end())
{
if (m_current != &m_header) // 如果当前在头结点就跳过
{
m_current = m_current->next;
i++;
}
else
{
m_current = m_current->next;
}
}
if (m_current == &m_header) // 移动过后如果当前在头结点
{
m_current = m_current->next;
}
return (i == this->m_step); //表示当前移动成功
}
bool pre()
{
int i = 0;
while ((i < this->m_step) && !end())
{
if (m_current != &m_header) // 如果当前在头结点就跳过
{
m_current = m_current->prev;
i++;
}
else
{
m_current = m_current->prev;
}
}
if (m_current == &m_header) // 移动过后如果当前在头结点
{
m_current = m_current->prev;
}
return (i == this->m_step); //表示当前移动成功
}
~DualCircleList()
{
clear();
}
};
}
#endif
测试代码
#include <iostream>
#include "DualCircleList.h"
using namespace std;
using namespace DTLib;
int main(void)
{
DualCircleList<int> dl;
for (int i = 0; i < 5; i++)
{
//dl.insert(0, i);
//dl.insert(0, 5);
dl.insert(i);
dl.insert(5);
}
cout << "begin delete..." << endl;
dl.move(dl.length() - 1); // 移动游标
while (dl.find(5) != -1)
{
if (dl.current() == 5)
{
cout << dl.current() << endl;
dl.remove(dl.find(dl.current()));
}
else
{
dl.pre();
}
}
cout << "end delete" << endl;
int i = 0;
for (dl.move(dl.length() - 1); (i < dl.length()) && !dl.end(); dl.pre(), i++)
{
cout << dl.current() << endl;
}
return 0;
}
测试输出
begin delete...
5
5
5
5
5
end delete
4
3
2
1
0
请按任意键继续. . .
至此,线性表相关的类已全部实现: