在介绍链表之前,先简单介绍一下缓存机制的三种策略:1、先进先出策略(FIFO),2、最少使用策略(LFU),3、最近最少使用策略(LRU)。单链表、循环链表、双向链表是我们最为常见的三种链表结构,一个链表是由多个链表节点连接而成,在单链表中,每个节点包含两个域:用来存储数据的数据域以及用来连接下一个节点的指针域(next),而在双向链表中指针域上不仅包含连接下一个节点的指针(next),还包含连接上一个节点的指针(pre)。另外,每个链表都会有个头指针,用来指向链表的第一个节点也就是链表的基地址,而在循环链表中最后一个节点的next指针指向的不是NULL,而是链表头指针,且双向循环链表中的头指针的prev指针指向的链表的最后一个节点。链表的插入和删除只需要考虑相邻节点指针的改变即可,所以时间复杂度为O(1),效率十分高,但是链表的随机访问的效率相对要低很多,因为链表无法像数组一样,通过首地址和下标,利用寻址公式直接计算得出对应的内存地址,而是需要指针一个节点一个节点的依次遍历,直到找到相应的节点为止,所以链表的随机访问时间复杂度为O(n),这里需要注意的是,双向链表如果要插入或删除指定节点时比单链表要高效多,虽然此时双向链表的时间复杂度为O(1)。链表相对于数组的优点是删除和插入相对高效,内存分配没有连续空间的要求,但缺点也很明显,节点中包含指针域,浪费内存,还有就是频繁的申请释放内存,容易产生内存碎片。结构如图所示:
不多说,直接上代码:
#include
#include
template
class Node
{
public:
T data;
Node(T& item);
Node* next;
Node* pre;
};
template
class LinkList
{
public:
LinkList();
~LinkList();
int getSize(void);
bool IsEmpty(void);
int gotoNext(void);
int setPostion(int pos);
int getPostion(void);
int InsertNodeBefore(T& data);
int InsertNodeAfter(T& data);
void DeleteNode(void);
void getCurrNodeData(T& data);
void setCurrNodeData(T& data);
void clear();
void print();
private:
Node* head;
Node* currNode;
int size;
int position;
void freeNode(Node* p);
};
#endif
// LinkedList.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include "LinkedList.h"
/* 链表节点构造函数 */
template
Node::Node(T& item)
{
data = item;
next = NULL;
pre = NULL;
}
/* 链表构造函数 */
template
LinkList::LinkList()
{
head = NULL;
currNode = NULL;
size = 0;
position = -1;
}
/* 链表析构函数 */
template
LinkList::~LinkList()
{
clear();
}
/* 获取链表长度 */
template
int LinkList::getSize(void)
{
return size;
}
/* 判断链表是否为空 */
template
bool LinkList::IsEmpty(void)
{
return size==0?true:false;
}
/* 移动到下个节点,返回下个节点的位置值 */
template
int LinkList::gotoNext(void)
{
if(NULL == head)
{
return -1;
}
if(NULL == currNode)
{
return -1;
}
else
{
currNode = currNode->next;
position = (position+1+1)%(size);
}
return position;
}
/* 将当前节点移动到指定节点值 */
template
int LinkList::setPostion(int pos)
{
if(pos >= size||pos < 0)
{
return -1;
}
position = 0;
currNode = head;
for(int i = 0; i < pos;i++)
{
position++;
currNode = currNode->next;
}
return position;
}
/* 获取当前节点的位置 */
template
int LinkList::getPostion(void)
{
return position;
}
/* 在当前节点前插入新节点 */
template
int LinkList::InsertNodeBefore(T& data)
{
Node* p = new Node(data);
if(0 == size)
{
head = p;
head->next = head;
head->pre = head;
currNode = head;
position++;
}
else
{
currNode->pre->next = p;
currNode->pre = p;
p->next = currNode;
p->pre = currNode->pre->next;
if(head == currNode)
{
head = p;
}
currNode = p;
}
size++;
return size;
}
/* 在当前节点后插入新节点 */
template
int LinkList::InsertNodeAfter(T& data)
{
Node* p = new Node(data);
if(0 == size)
{
head = p;
head->next = head;
head->pre = head;
currNode = p;
}
else
{
currNode->next->pre = p;
p->next = currNode->next ;
currNode->next = p;
p->pre = currNode;
currNode = p;
}
size++;
position++;
return size;
}
/* 删除当前节点 */
template
void LinkList::DeleteNode(void)
{
if(0 == size)
{
return;
}
Node* p = currNode;
currNode->pre->next = currNode->next;
currNode->next->pre = currNode->pre;
if(head == currNode)
{
head = currNode->next;
}
currNode = currNode->next;
freeNode(p);
size--;
return ;
}
/* 释放指定节点的内存 */
template
void LinkList::freeNode(Node* p)
{
if(!p)
{
delete p;
}
return;
}
/* 获取当前节点的数据 */
template
void LinkList::getCurrNodeData(T& data)
{
if(currNode)
{
data = currNode->data;
}
return ;
}
/* 修改当前节点的数据 */
template
void LinkList::setCurrNodeData(T& data)
{
if(currNode)
{
currNode->data = data;
}
return ;
}
/* 清空链表 */
template
void LinkList::clear()
{
Node* p = currNode;
for(int i = 0;i < size;i++)
{
p = p->next;
freeNode(currNode);
currNode = p;
}
head = NULL;
currNode = NULL;
size = 0;
position = -1;
return;
}
template
void LinkList::print()
{
Node* p = head;
for(int i = 0;i < size;i++)
{
std::cout<<"data = "<data<next;
}
std::cout<<"====================================== "< linklist;
linklist.InsertNodeAfter(a);
linklist.InsertNodeAfter(b);
linklist.InsertNodeAfter(c);
linklist.InsertNodeAfter(d);
linklist.InsertNodeAfter(e);
linklist.print();
std::cin.get();
return 0;
}
另外附上单向不循环链表的代码,供读者对比区别使用:
// 单链表.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
template
class Node
{
public:
T data;
Node(T& item);
Node* next;
};
template
class LinkList
{
public:
LinkList();
~LinkList();
int getSize(void);
bool IsEmpty(void);
int gotoNext(void);
int getPostion(void);
int InsertNode(T& data);
int DeleteNode(void);
void getCurrNodeData(T& data);
void setCurrNodeData(T& data);
void clear();
void print();
private:
Node* head;
Node* currNode;
int size;
int position;
void freeNode(Node* p);
};
/* 链表节点构造函数 */
template
Node::Node(T& item)
{
data = item;
next = NULL;
}
/* 链表构造函数 */
template
LinkList::LinkList()
{
head = NULL;
currNode = NULL;
size = 0;
position = -1;
}
/* 链表析构函数 */
template
LinkList::~LinkList()
{
clear();
}
/* 获取链表长度 */
template
int LinkList::getSize(void)
{
return size;
}
/* 判断链表是否为空 */
template
bool LinkList::IsEmpty(void)
{
return size==0?true:false;
}
/* 移动到下个节点,返回下个节点的位置值 */
template
int LinkList::gotoNext(void)
{
if(NULL == head)
{
return -1;
}
if(NULL == currNode)
{
return -1;
}
else
{
currNode = currNode->next;
position++
}
return position;
}
/* 获取当前节点的位置 */
template
int LinkList::getPostion(void)
{
return position;
}
/* 在当前节点前插入新节点 */
template
int LinkList::InsertNode(T& data)
{
Node* p = new Node(data);
if(0 == size)
{
head = p;
head->next = NULL;
currNode = p;
}
else
{
p->next = currNode->next;
currNode->next = p;
currNode = p;
}
size++;
position++;
return size;
}
/* 删除当前节点 */
template
int LinkList::DeleteNode(void)
{
if(0 == size)
{
return -1;
}
Node* p = head;
Node* tmp;
for(int i = 0;i < size;i++)
{
if(NULL == p)
{
return -1;
}
if(p->next == currNode)
{
p->next = currNode->next;
break;
}
p = p->next;
}
tmp = currNode;
if(currNode == head)
{
head = currNode->next;
}
if(NULL == currNode->next)
{
position--;
currNode = p;
}
else
{
currNode = currNode->next;
}
freeNode(p);
size--;
if(0 == size)
{
position = -1;
}
return 0;
}
/* 释放指定节点的内存 */
template
void LinkList::freeNode(Node* p)
{
if(!p)
{
delete p;
}
return;
}
/* 获取当前节点的数据 */
template
void LinkList::getCurrNodeData(T& data)
{
if(currNode)
{
data = currNode->data;
}
return ;
}
/* 修改当前节点的数据 */
template
void LinkList::setCurrNodeData(T& data)
{
if(currNode)
{
currNode->data = data;
}
return ;
}
/* 清空链表 */
template
void LinkList::clear()
{
if(0 == size)
{
return;
}
Node* p = head;
Node* tmp = head->next;
while(p)
{
freeNode(p);
p = tmp;
if(tmp)
{
tmp = tmp->next;
}
}
head = NULL;
currNode = NULL;
size = 0;
position = -1;
return;
}
template
void LinkList::print()
{
if(0 == size)
{
return;
}
Node* p = head;
Node* tmp = head->next;
while(p)
{
std::cout<data<next;
}
}
return;
}
int main(int argc, _TCHAR* argv[])
{
int a = 10,b=20,c=30,d=40,e=50;
LinkList list;
list.InsertNode(a);
list.InsertNode(b);
list.InsertNode(c);
list.DeleteNode();
list.InsertNode(d);
list.InsertNode(e);
list.print();
std::cin.get();
return 0;
}