之前通过C语言实现了单链表,今天我们来看看C++如何实现单链表?
下面是主代码:
#include<iostream>
#include<assert.h>
using namespace std;
typedef int DataType;
struct SListNode //创建节点
{
DataType data;
SListNode* next;
SListNode(DataType x)
:data(x),next(NULL)
{}
};
class SList
{
typedef SListNode Node;
public:
SList()
:_head(NULL),_tail(NULL)
{}
SList(const SList& s)
:_head(NULL),_tail(NULL)
{
if (s._head == NULL)
{
return;
}
else
{
Node* cur = s._head;
while (cur)
{
PushBack(cur->data);
cur = cur->next;
}
}
}
//SList& operator=(const SList& s) //传统写法
//{
// if (this != &s)
// {
// _head = NULL;
// _tail = NULL;
// Node* cur = s._head;
// while (cur)
// {
// //if (_head == NULL)
// //{
// // _head = new Node(s._head->data);
// // _tail = _head;
// //}
// //else
// //{
// // _tail->next = new Node(cur->data);
// // _tail = _tail->next;
// //}
// PushBack(cur->data);
// cur = cur->next;
// }
// _tail->next = NULL;
// }
// return *this;
//}
void Swap(SList& s)
{
swap(_head, s._head);
swap(_tail, s._tail);
}
//SList& operator=(const SList& s) //现代写法
//{
// if (this != &s)
// {
// SList tmp(s);
// Swap(tmp);
// }
// return *this;
//}
SList& operator=(const SList s) //现代写法再优化
{
if (this != &s)
{
swap(_head, s._head);
swap(_tail, s._tail);
}
return *this;
}
~SList()
{
Destory();
}
void PushBack(DataType x)
{
if (_head == NULL)
{
_head = new Node(x);
_tail = _head;
}
else
{
_tail->next = new Node(x);
_tail = _tail->next;
}
return;
}
void PopBack()
{
if (_head == NULL)
{
return;
}
else if (_head->next == NULL) //else if(_head == _tail)
{
delete _tail;
_tail = NULL;
_head = NULL;
return;
}
else
{
Node* cur = _head;
while(cur->next != _tail)
{
cur = cur->next;
}
delete _tail;
_tail = cur;
_tail->next = NULL;
return;
}
}
void PushFront(DataType x)
{
if (_head == NULL)
{
_head = new Node(x);
_head = _tail;
//PushBack(x);
}
else
{
Node* cur = _head;
_head = new Node(x);
_head->next = cur;
}
return;
}
void PopPront()
{
if (_head == NULL)
{
return;
}
else if (_head == _tail)
{
delete _tail;
_head = _tail = NULL;
}
else
{
Node* cur = _head;
cur = cur->next;
delete _head;
_head = cur;
}
return;
}
void Insert(Node* pos, DataType x)
{
assert(pos);
if (pos == _head)
{
PushFront(x);
}
else
{
Node* cur = _head;
while (cur->next != pos)
{
cur = cur->next;
}
cur->next = new Node(x);
cur->next -> next = pos;
}
}
void Erase(Node* pos)
{
assert(pos);
if (pos == _head)
{
PopPront();
}
else if (pos == _tail)
{
PopBack();
}
else
{
Node* cur = _head;
while (cur->next != pos)
{
cur = cur->next;
}
cur->next = pos->next;
delete pos;
}
return;
}
Node* Find(DataType x)
{
Node* cur = _head;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
}
void Destory()
{
while (_head)
{
Node* cur = _head;
_head = _head->next;
delete cur;
}
_head = _tail = NULL;
}
int Length()
{
if (_head == NULL)
{
return 0;
}
else
{
int count = 0;
Node* cur = _head;
while (cur)
{
count++;
cur = cur->next;
}
return count;
}
}
void Reverse() //链表逆置
{
if (_head == NULL || _head->next == NULL)
{
return;
}
Node* cur = _head;
Node* pre = _head;
Node* del = _head->next;
while (cur->next)
{
PushFront(cur->next->data);
cur = cur->next;
}
while (del)
{
Node* pdel = del;
del = del->next;
delete pdel;
}
_tail = pre;
_tail->next = NULL;
}
void Display()
{
Node* cur = _head;
while (cur)
{
cout << cur->data << "->";
cur = cur->next;
}
cout << endl;
}
private:
Node* _head;
Node* _tail;
};
int main()
{
SList s1;
s1.PushBack(1);
s1.PushBack(2);
s1.PushBack(3);
s1.PushBack(4);
s1.Display();
//s1.PopBack();
//s1.PopBack();
//s1.PopBack();
//s1.PopBack();
//s1.PushFront(0);
//s1.PopPront();
//s1.PopPront();
//s1.PopPront();
//s1.PopPront();
//s1.PopPront();
//s1.Insert(s1.Find(3), 9);
//s1.Erase(s1.Find(1));
//s1.Erase(s1.Find(1));
//s1.Erase(s1.Find(1));
//s1.Erase(s1.Find(1));
//s1.Erase(s1.Find(1));
//s1.Destory();
//s1.Display();
//int ret = s1.Length();
//cout << ret << endl;
//s1.Reverse();
SList s2(s1);
SList s3;
s3 = s1;
s2.Display();
s3.Display();
system("pause");
return 0;
}
如上面代码:实现了以下有关单链表的功能
SList(); //构造函数
SList(const SList& s); //拷贝构造函数
SList& operator=(SList& s); // 赋值运算符重载
~SList(); //析构函数
void PushBack(DataType x); //尾插
void PopBack(); //尾删
void PushFront(DataType x); // 头插
void PopPront(); //头删
void Insert(Node* pos, DataType x); // 指定位置插入(pos前个位置插入)
void Erase(Node* pos); //指定位置删除
Node* Find(DataType x); //查找位置
void Destory(); // 清空链表
int Length(); //链表长度
void Reverse(); //链表逆置
void Display(); //打印
其中,赋值运算符的重载这个函数使用了三种方法,传统写法,现代写法以及优化后的现代写法。
对于拷贝构造函数,我们重新定义,因为这涉及深浅拷贝的问题(深拷贝就是先开辟空间后拷贝。浅拷贝是不用开辟速与自己的存储空间,而是直接指向原有的空间,也就是说两对象使用同一块空间,这在析构函数调用时就会出现问题,因为为了释放内存,析构函数也是重新定义的,两个对象需要调用两次析构函数,也就是说需要释放空间两次,而两对象只有一块内存,当地一次释放后,再对这块内存进行释放操作就会出现问题,解决浅拷贝带来的问题,就是利用写时拷贝。扯远了。。。有兴趣可以查看我有关写时拷贝的文章)。这里的拷贝构造函数我用了深拷贝。另外这里的链表逆置(采用头插方式)以及指定位置插入(pos位置前插)都是面试题的常客,需要好好学习。
至于细节上得自己把握,下面这个问题我就犯了好几次。在进行尾删这类操作时,一定要对尾指针_tail进行操作。没有节点时,_tail=_head=NULL;有节点时,需保存待删除前一个节点,这个节点就是删除尾节点后的新的尾节点,需要将_tail->next=NULL;还有就是new与delete,new[]与delete[]必须成对使用。这类问题都必须自己多注意,代码垒的多了问题就少了。加油!!!