一.链表
链表是存储和访问数据的一种结构,与数组类似,但链表在内存中是不连续的,而数组在内存中连续存储。
二.利用C++实现链表的两种方法
1.结构体(struct)
2.类(class)
一个完整的链表由两部分组成:节点类和链表类。
节点类是存储数据的部分,一般包含两类成员:存储的数据和指向下一个节点的指针。这个指针目的在于把一个个节点串起来形成一个整体。
class Node //节点类
{
public:
int num; //节点存储的数据值
Node* next; //指向下一个节点的指针
};
链表类起着提纲挈领的作用,一般包含头指针、链表节点总数和操作函数。头指针指向链表的第一个节点,由于每个节点都包含一个指向下一个节点的指针,所以这样就把所有节点和起总纲作用的链表类串在一起,形成一个完整的链表。链表节点的总数用于定位链表内的节点。链表类内的成员函数是对链表进行操作的入口。
//链表类
class List
{
public:
Node *head; //头指针
int nodeConut; //节点总数
//无参构造函数赋初值
List()
{
head=nullptr;
nodeCount=0;
}
//操作函数
Node* Move(); //返回链表最后一个节点
void Insert(Node* node); //在链表尾部插入新节点,即给链表填充节点
void passList(); //遍历输出所有节点
~List(); //析构函数释放所有节点
}
返回链表的最后一个节点,为在尾部新增节点做准备。
//返回链表最后一个节点
Node* List::Move()
{
Node *t=head;
for(int i=1;i<nodeCount;i++) //n个节点t只需移动n-1次
{
t=t->next; //把下一个节点的位置赋给t
}
return t;
}
在链表的末尾新增节点。
//在尾部插入节点
void List::Insert(Node* node)
{
//首先判断链表是否为空
if(head==nullptr)
{
head=node; //把node赋给头节点
}
else
{
Move()->next=node; //把node赋给末节点的下一个节点
}
nodeCount++; //节点总数加一
}
遍历输出节点。
//遍历输出节点
void List::passList()
{
if(head==nullptr)
{
cout<<"Node is empty.";
}
else
{
Node *p=head; //新建一个指针指向头指针
for(int i=1;i<=nodeCount;i++)
{
cout<<p->num<<' ';
p=p->next; //p指向下一节点,不断移动
}
}
}
析构函数。
//析构函数释放所有节点
List::~List()
{
if(nodeCount>0)
{
//定义一个指针指向头节点
Node *p=head;
Node *q=nullptr; //先遍历再释放,则头节点不能释放;先释放再遍历,则不能遍历;因此引入新的中间变量
for(int i=1;i<=nodeCount;i++)
{
q=p->next;
delete p;
p=q;
}
p=nullptr;
q=nullptr;
head=nullptr;
nodeCount=0;
}
}
主函数。
int main()
{
//定义链表
List list; //创建节点并赋值
int n; //要输入的数据个数
int *p=new int(n);
for(int i=1;i<=*p;i++)
{
int m=0; //输入的数据
cin>>m;
Node *pNode=new Node;
pNode->num=m;
list.Insert(pNode); //把新节点插入到链表最后
}
list.passList(); //遍历输出链表
return 0;
}