概要:本期主要讲解数组和单链表的结构、它们之间的区别以及单链表的操作实现。
一、什么是数组?
数组是一组地址空间相连 的内存单元组成的有限序列。
如下图所示:
上面展示的是一个长度为4的int型数组Array,数组的下标从0开始
数组由于在内存中是连续的地址存储,支持随机访问,可以通过数组下标访问元素,时间复杂度的是O(1),但若是对数组进行插入、删除操作,其平均时间复杂度是O(n),原因是对数组元素进行插入或者删除操作时,该元素的后面元素都需要进行后移或者前移的操作。
二、什么是单链表?
链表是一组 任意的 内存单元组成的有序序列。
如下图所示:
上面展示的是单链表的结构。
一个存储单元分为指针域和数据域,顾名思义,指针域存储的是单元在内存中的地址,数据域存储的是数据元素。因此链表相对于数组会更消耗内存空间
由于链表在内存中的分布是离散的,每次访问某个数据只能通过前一个元素来找后一个元素,所以,链表的查询、遍历的平均时间复杂是O(n),但是若进行链表的插入、删除操作,其平均时间复杂度为O(1),原因是对链表进行删除节点操作,只需要将其的前一节点的指针指向其后一节点。而实现链表的插入节点操作,只需要将该节点的指针指向添加节点的数据域,再将添加节点的指针指向原先节点的后一节点的数据域。
单链表的节点删除如下图所示:
单链表的节点插入如下图所示:
三、附上单链表的操作C++实现:
0.单链表结构和初始化
创建一个单链表类LinkedList,再声明一个链表节点类作为其成员变量。
//结构
class LinkedList
{
private:
class Node
{
public:
Node *next;
QString data;
};
Node *head;
int length = 0;
public:
LinkedList();
};
LinkedList::LinkedList()
{
head = new Node;
head->data = "";
head->next = nullptr;
length = 0;
}
1.创建单链表
尾插法
//尾插法创建n个节点的链表(顺序)
void LinkedList::TailCreateLinkedList(int n)
{
Node *pre = head;
length = n;
int i = 0;
while (i < n) {
qDebug()<< QStringLiteral("请输入第") << i << QStringLiteral("个结点的数据:");
Node *cur = new Node;
string str;
cin >> str;
cur->data = QString::fromStdString(str);
++i;
pre->next = cur;
pre = cur;
cur->next = nullptr;
}
}
头插法
//头插法创建n个节点的链表(逆序)
void LinkedList::HeadCreateLinkedList(int n)
{
Node *pre = head;
length = n;
int i = 0;
while (i < n) {
qDebug()<< QStringLiteral("请输入第") << i << QStringLiteral("个结点的数据:");
Node *cur = new Node;
string str;
cin >> str;
cur->data = QString::fromStdString(str);
++i;
cur->next = pre->next;
pre->next = cur;
}
}
2.打印单链表
//打印链表内容
void LinkedList::DisplayLinkedList()
{
if(length == 0)
{
qDebug()<<QStringLiteral("链表为空!")<<endl;
return ;
}
Node *_node = head->next;//节点1
int i = 0;
while(_node)
{
qDebug()<<QStringLiteral("第")<<i++<<QStringLiteral("个节点的数据:")<<_node->data<<endl;
if(_node->next == nullptr)
{
return ;
}
_node = _node->next;
}
}
3.查询节点位置
//查询节点位置
int LinkedList::GetNodeIndex(QString data)
{
if(length == 0)
{
qDebug()<<QStringLiteral("链表为空!")<<endl;
return -1;
}
Node *_node = head->next;//节点1
int i = 0;
while(_node)
{
if(_node->data == data)
{
qDebug()<<QStringLiteral("节点位置为:")<< i <<endl;
return i;
}
if(_node->next == nullptr)
{
qDebug()<<QStringLiteral("节点不存在!")<<endl;
return -1;
}
_node = _node->next;
i++;
}
}
4.插入节点到指定位置
//在指定位置后插入节点(前插可以参照后插实现)
void LinkedList::BackInsertNodeToLinkedList(int index,QString data)
{
if(index < 0 || index >=length)
{
qDebug()<<QStringLiteral("输入位置有误!")<<endl;
return ;
}
Node *_node = new Node;
if(length == 0)
{
_node = head;
}
else
{
_node = head->next;
}
int i = 0;
while(_node)
{
if(i == index)
{
Node* _nextNode = _node->next;//记录未插入是index位置的下一节点
Node *_newNode = new Node;//创建新节点
_newNode->data = data;
_node->next = _newNode;
_newNode->next = _nextNode;
qDebug()<<QStringLiteral("节点插入成功!")<<endl;
length++;
return ;
}
if(_node->next == nullptr)
{
qDebug()<<QStringLiteral("节点插入失败!")<<endl;
return ;
}
_node = _node->next;
i++;
}
}
5.删除单链表指定节点
//删除指定位置节点
void LinkedList::DeleteNodeInLinkedList(int index)
{
if(index < 0 || index >=length)
{
qDebug()<<QStringLiteral("输入位置有误!")<<endl;
return ;
}
Node *_node = new Node;
if(length == 0)
{
_node = head;
}
else
{
_node = head->next;
}
int i = 0;
while(_node)
{
if(i == index-1)//当前为index位置前一节点
{
Node* _delNode = _node->next;
Node* _nextNextNode = _node->next->next;//记录index位置的下一节点
_node->next = _nextNextNode;
delete _delNode;
_delNode = NULL;
length--;
qDebug()<<QStringLiteral("节点删除成功!")<<endl;
return ;
}
if(_node->next == nullptr)
{
qDebug()<<QStringLiteral("节点删除失败!")<<endl;
return ;
}
_node = _node->next;
i++;
}
}
6.获取单链表长度
//获取链表长度
int LinkedList::GetLinkedListLength()
{
Node *_node = head->next;
int i = 0;
while(_node)
{
i++;
_node = _node->next;
}
length = i;
qDebug()<<QStringLiteral("链表长度为:")<< length <<endl;
return length;
}