在C++中,链表是一种动态数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。链表具有灵活的内存管理和高校的插入与删除操作,但访问效率较低。链表的每个节点通常包含两部分:1、数据部分(存储链表中元素的数据);2、指针部分(指向链表中的下一个节点)。
链表类型主要有:1、单链表(每个节点只有一个指向下一个节点的指针);2、双向链表(每个节点包含指向下一个节点和前一个节点的指针);3、循环链表(最后一个节点指向链表的头节点)。
下面直接结合代码说明链表的创建和基本操作:
#include<iostream>
using namespace std;
struct Node{
int value;
Node* next;
//***构造函数的定义,Node(传入数据): 结构体变量(赋值数据),结构体变量(赋值数据){}。
Node(int Data): value(Data), next(nullptr){}
};
class LinkedList{
private:
//***后续不能再出现Node* head(已定义过),会因重复定义导致原有的head被覆盖产生bug
Node* head;
public:
LinkedList(): head(nullptr){}
~LinkedList(){
if(head!=nullptr){
while(head->next != nullptr){
Node* temp = head->next;
head->next = temp->next;
//删除temp指针及为清空temp指针所指向的Node节点的所有数据(数据部分和指针地址)
delete temp;
}
}
}
//插入元素到链表头部
void input_left(int data){
Node* newnode = new Node(data);
if(head == nullptr){
head = newnode;
return;
}
Node* current = head;
head = newnode;
head->next = current;
//head->next = head(无意义,head = head->next有意义), 错误代码:不能把自己的地址赋值给自己指向的地址,在head = newnode时将原有地址进行了覆盖
}
//插入元素到链表尾部
void input_right(int data){
Node* newnode = new Node(data);
if(head == nullptr){
head = newnode;
return;
}
if(head->next == nullptr){
head->next = newnode;
return;
}
Node* current = head->next;
while(current->next != nullptr){
//由于current在上面已经定义并初始化Node* current = head->next,因此下面再使用current时直接调用赋值即可,不需要再重新Node* current定义申明了
current = current->next;
}
current->next = newnode;
}
//打印链表中的每个元素
void print_list(){
Node* current = head;
if(current==nullptr){
cout<<"链表为空"<<endl;
return;
}
if(current->next == nullptr){
cout<<current->value<<"->"<<"nullptr";
}
while(current->next != nullptr){
cout<<current->value<<"->";
current = current->next;
}
cout<<current->value<<"->nullptr"<<endl;
}
//删除链表中的某个元素
void delete_list(int data){
Node* current = head;
if(current==nullptr){
cout<<"链表为空"<<endl;
return;
}
if(current->value==data){
head = head->next;
delete current;
return;
}
//***分清current->next !=nullptr && current->next->value != data先后顺序
//如果current->next已经为nullptr空时,再引用current->next->valu会报错!!!
while(current->next !=nullptr && current->next->value != data){
current = current->next;
}
if(current->next==nullptr){
cout<<"链表中并没有此元素"<<endl;
return;
}
if(current->next->value == data){
Node* deletenode = current->next;
current->next = deletenode->next;
delete deletenode;
return;
}
}
};
int main(){
//ListNode* node = new ListNode(); // 带有new标记,确保分配内存,仅定义时不分配内存
LinkedList list1;
list1.input_right(4);
list1.input_right(3);
list1.input_right(1);
list1.input_right(6);
list1.input_right(0);
list1.input_right(7);
list1.input_left(10);
list1.input_right(15);
list1.input_right(6);
list1.print_list();
list1.delete_list(16);
list1.print_list();
cout<<"学好C++,走遍天下都不怕!"<<endl;
}
上面展示了链表创建(构造和析构函数)、链表的插入(从头部和尾部插入)、链表的删除(指定元素的删除)。标记***的为笔者在编写的时候出现的一些需要特殊注意的问题,总结如下:
1、在构造函数中,有一种简便的书写方式格式如:Node(int 传入参数): value(传入参数), next(nullptr){},其中value(输入参数),value表示结构体中存在的变量,(输入参数)表示外部传入或指定常量。
2、在if、while进行循环判断语句时,if( current->next != nullptr && current->next->value != data),尤其是and(&&)时,是有先后顺序的,当current->next不为空时(空,即为current->next未分配地址内存),current->next->value才有意义,即C++总是只能访问被分配地址内存的数据。
3、ListNode* node = new ListNode();带有new标记时,才确保定义的ListNode类型,命名为node的指针对象被分配了内存。如果仅为ListNode* node;未被new标记,则仅为定义声明的情况下,命名为node的指针对象未被计算机分配内存(内存即为地址,通过指针可以查找)。
以上为笔者在创建链表和基本操作时遇到的一些注意问题,如有问题可以随时私信与我交流!
标签:Node,current,head,nullptr,C++,next,链表,基本操作 From: https://blog.csdn.net/qq_43287713/article/details/144352803