链表
数据结构中的每个节点都对应一个存储单位,这种存储单元称之为存储结点。结点有两个部分组成,一是数据域,用来存储数据;二是指针域,用来存放指向前一个或者后一个结点的指针。链表按照连接的方式分为三种,分别是单链表、循环链表、双向链表。
1、单链表
基本思想:指向单链表的第一个结点的指针,用head表示,称为头指针;data表示数据域,next表示指针域;尾结点的指针域为NULL,并且当头指针为NULL时,表示链表是一个空表。
算法思路:单链表主要的功能是对表的插入和删除,因为单链表有指针域的存在,对于插入和删除操作来说只需要修改“链”就能实现,不需要像数组那样要移动数据。
1、单链表的头插
单链表的头插只需要将待插入的结点的指针域指向头节点的下一个结点,并将头节点的指针域指向待插入的结点就完成了。
(1)
(2)
(3)
2、单链表的尾插
(1)
(2)
(3)
3、单链表的删除
(1)
(2)
(3)
代码实现:
单链表的结构
//单链表
class SimpleList
{
public:
SimpleList(){} //构造函数
~SimpleList(){} //析构函数
void InsertHead(int val); //头插
void InsertTail(int val); //尾插
void Remove(int val); //删除
bool FindValue(int val); //查找
bool Empty(); //判空
int Front(); //获取头元素
void DeleteFront(); //删除头元素
void Show(); //打印数据
private:
class Node
{
public:
Node(int data = 0) :_data(data), _next(nullptr) {}
private:
int _data;
Node* _next;
friend class SimpleList;
};
Node* _head;
};
1、单链表的头插
void InsertHead(int val)
{
Node *tmp = new Node(val);
tmp->_next = _head->_next;
_head->_next = tmp;
}
2、单链表的尾插
void InsertTail(int val)
{
Node *tail = _head;
while (tail->_next != nullptr)
{
tail = tail->_next;
}
tail->_next = new Node(val);
}
3、单链表的删除
Node *tmp = _head;
Node *del = _head->_next;
while (del != nullptr)
{
if (del->_data == val)
{
tmp->_next = del->_next;
delete del;
del = tmp->_next;
}
tmp = del;
del = del->_next;
}
2、循环链表
基本思想:循环链表和单链表相似,但是循环链表尾结点的指针域保存的是头节点的指针。
算法思路:带头结点的循环链表的操作与单链表相似,只是遍历链表的算法只要将单链表中的判断终止条件由NULL该为head就可以了,但需要注意的是循环链表的删除。
循环链表的删除:
(1)
(2)
代码实现:
循环链表的结构
class CircleList
{
public:
CircleList() //构造函数
{
_head = new Node();
_head->_next = _head;
}
~CircleList() //析构函数
{
Node* tmp = _head;
Node* tail = _head->_next;
while (tail != _head)
{
tail = tail->_next;
}
while (tmp != tail)
{
_head = _head->_next;
delete tmp;
tmp = _head;
}
delete _head;
}
void InsertHead(int val); //头插
void InsertTail(int val); //尾插
void Remove(int val); //删除指定值
bool FindValue(int val); //查找
bool Empty(); //判空
int Front(); //获取头结点
void DeleteFront(); //删除头节点
void Show(); //展示
private:
class Node
{
public:
Node(int data = 0) :_data(data) {}
private:
int _data;
Node* _next;
friend class CircleList;
};
Node* _head;
}
循环链表的删除
void Remove(int val)
{
Node *tmp = _head;
Node *del = _head->_next;
while (del != _head)
{
if (del->_data == val)
{
break;
}
tmp = del;
del = del->_next;
}
if (del == nullptr)
{
cout << "Remove Error" << endl;
return;
}
if (tmp == _head)
{
_head->_next = del->_next;
tmp->_next = del->_next;
delete del;
}
else
{
tmp->_next = del->_next;
delete del;
}
}
3、双向链表
基本思想:双向链表与上面单链表和循环链表不同在于,双向链表的每个结点的指针域除了有指向后一个结点的指针还有指向前一个结点的指针,即一个指向前驱一个指向后继。
算法思路:双向链表的操作更灵活,
1、双向链表的头插
(1)
(2)
2、双向链表的尾插
(1)
(2)
3、双向链表的删除
(1)是尾结点
(2)不是尾结点
代码实现:
双向链表的结构
class TwoWardList
{
public:
TwoWardList() //构造函数
{
_head = new Node();
_head->_next = nullptr;
_head->_rear = nullptr;
}
~TwoWardList() //析构函数
{
Node* tmp = _head;
while (tmp != nullptr)
{
_head = _head->_next;
delete tmp;
tmp = _head;
}
delete _head;
}
void InsertHead(int val); //头插
void InsertTail(int val); //尾插
void Remove(int val); //删除指定值
bool FindValue(int val); //查找指定值
bool Empty(); //判空
int Front(); //获取头节点的值
void DeleteFront(); //删除头节点
void Show(); //打印
private:
class Node
{
public:
Node(int data = 0) :_data(data),_next(nullptr),_rear(nullptr) {}
private:
int _data;
Node* _next;
Node* _rear;
friend class TwoWardList;
};
Node* _head;
};
双向链表的头插
void InsertHead(int val)
{
Node* tmp = new Node(val);
tmp->_next = _head->_next;
_head->_next = tmp;
tmp->_rear = _head;
if (tmp->_next != nullptr)
{
tmp->_next->_rear = tmp;
}
}
双向链表的尾插
void InsertTail(int val)
{
Node *tmp = new Node(val);
Node *cur = _head;
while (cur->_next != nullptr)
{
cur = cur->_next;
}
cur->_next = tmp;
tmp->_rear = cur;
tmp->_next = nullptr;
}
双向链表的删除
void Remove(int val)
{
Node *cur = _head->_next;
while (cur != nullptr)
{
if (cur->_data == val)
{
break;
}
cur = cur->_next;
}
if (cur == nullptr)
{
return;
}
cur->_rear->_next = cur->_next;
if (cur->_next != nullptr)
{
cur->_next->_rear = cur->_rear;
}
delete cur;
}