链表操作
我们在讲C++的时候,详细讲解过数组。并指出数组的大小是提前声明好以及在内存中存储是连续的地址,正式因为是连续地址,这就导致了一些问题。例如,我们如果要在数组中间添加一些数据,则需要后面所有的数据都要随着移动。这就给数据处理带来了很多不便,因此针对这个问题,数据结构中提供了链表操作。
链表操作主要包括六种:单向链表、双向链表、循环链表、跳跃链表、自组织链表、稀疏链表。下面说一下链表当中的基本单元,链表当中主要包括内容信息和指向链表指针。我们从下面图来详细讲解:
从上图我们可以看出,指针P指向链表中10所在节点1的内存地址;节点1中的指针指向节点2(数据8)所在地址;节点2中的指针指向节点3(数据50)所在地址,节点3中的指针指向空地址。
单向链表
单向链表,我们从名字上就应该意识到,这个其实就是一直向同一方向指向的链表。下面我们通过程序来查看:
#include <iostream>
using namespace std;
//单向链表类
class ListClass
{
public:
ListClass();
~ListClass();
ListClass(int iTmpVar, ListClass *iTmpList);
int info;
ListClass *next;
private:
};
ListClass::ListClass()
{
next = 0;
}
ListClass::ListClass(int iTmpVar, ListClass *iTmpList = NULL)
{
info = iTmpVar;
next = iTmpList;
}
ListClass::~ListClass(){}
int main()
{
ListClass *listVar = new ListClass(10, NULL);
listVar->next = new ListClass(11, NULL);
listVar->next->next = new ListClass(12, NULL);
//访问每个链表的信息,并进行打印
cout << listVar->info << " " << listVar->next->info << " "<< listVar->next->next->info<< endl;
getchar();
}
运行结果
10 11 12
我们可以看到,单向链表如果只保留head头指针,要访问最后的数据则需要依次访问中间所有的指针,直到指向最后的数据才可以。因此,我们需要引入指向末尾的指针tail。下面我们来看一下添加了head和tail指针后的实例:
#include <iostream>
#include <list>
using namespace std;
//单向链表节点类
class ListNodeClass
{
public:
ListNodeClass();
~ListNodeClass();
ListNodeClass(int iTmpVar, ListNodeClass *iTmpList);
int info;
ListNodeClass *next;
private:
};
//单向链表类
ListNodeClass::ListNodeClass()
{
next = 0;
}
ListNodeClass::ListNodeClass(int iTmpVar, ListNodeClass *iTmpList = NULL)
{
info = iTmpVar;
next = iTmpList;
}
ListNodeClass::~ListNodeClass() {}
class InitListClass
{
public:
InitListClass();
~InitListClass();
void addToHead(int iTmp);
void addToTail(int iTmp);
int deleteFromHead();
int deleteFromTail();
void deleteNode(int iTmp);
bool isInList(int iTmp) const;
private:
ListNodeClass *head, *tail;
};
/*初始头和尾指针为空指针*/
InitListClass::InitListClass()
{
head = tail = NULL;
}
/*添加头信息*/
void InitListClass::addToHead(int iTmp)
{
head = new ListNodeClass(iTmp, head);
if (tail == NULL)
tail = head; //头和尾指向同一地址
}
/*添加尾信息*/
void InitListClass::addToTail(int iTmp)
{
if (tail != NULL)
{
tail->next = new ListNodeClass(iTmp); //添加下一节点
tail = tail->next;
}
else
head = tail = new ListNodeClass(iTmp);
}
/*从头删除信息*/
int InitListClass::deleteFromHead()
{
int iReturnInfo = head->info;
ListNodeClass *tmpClass = head;
if (head == tail)
head = tail = NULL;
else
head = head->next;
delete tmpClass;
return iReturnInfo;
}
/*从尾删除信息*/
int InitListClass::deleteFromTail()
{
int iReturnInfo = tail->info;
if (head == tail) //链表中只有一个节点
{
delete head;
head = tail = NULL;
}
else
{
ListNodeClass *tmpClass;
for (tmpClass = head; tmpClass->next != tail; tmpClass = tmpClass->next) //循环指向尾节点上一节点
delete tail;
tail = tmpClass;
tail->next = NULL;
}
return iReturnInfo;
}
/*删除节点*/
void InitListClass::deleteNode(int iTmp)
{
if (head != NULL)
{
if (head == tail && iTmp == head->info) //链表只有一个数据
{
delete head;
head = tail = NULL;
}
else if (iTmp == head->info) //链表超过一个数据,其中删除的节点为数据头
{
ListNodeClass *tmpClass = head;
head = head->next;
delete tmpClass;
}
else
{
ListNodeClass *predClass, *tmpClass;
for (predClass = head, tmpClass = head->next; tmpClass != NULL && !(tmpClass->info == iTmp); predClass = predClass->next, tmpClass = tmpClass->next);
if (tmpClass != NULL)
{
predClass->next = tmpClass->next;
if (tmpClass == tail)
tail = predClass;
delete tmpClass;
}
}
}
}
/*判断链表中是否存在指定数据*/
bool InitListClass::isInList(int iTmp) const
{
ListNodeClass *tmpClass;
for (tmpClass = head; tmpClass != NULL && !(tmpClass->info == iTmp); tmpClass = tmpClass->next); //遍历链表中数据,并进行一一对比
return tmpClass != NULL;
}
InitListClass::~InitListClass() {}
int main()
{
InitListClass *listVar = new InitListClass(); //创建链表
listVar->addToHead(10);
listVar->addToTail(9); //在尾部添加数据
listVar->addToTail(8);
//cout << listVar->deleteFromHead() << endl; //从头开始删除数据
//cout << listVar->deleteFromHead() << endl;
//cout << listVar->deleteFromHead() << endl;
listVar->deleteNode(8); //删除节点内的8信息
cout << listVar->isInList(8) << endl; //判断数据是否存在
getchar();
}
运行结果
0
下面我们来聊一聊链表中的插入、删除、查找操作:
更多《计算机视觉与图形学》知识,可关注下方公众号: