#include<iostream>
#include<stdexcept>
using namespace std;
#define eleType int
这段代码包含了 C++ 的标准输入输出库 <iostream>
和异常库 <stdexcept>
的引用,此外,我们定义了一个宏 eleType
,将 int
类型定义为 eleType
。这样做的好处是,如果以后需要修改数据类型,只需要修改宏定义即可,而不必在代码中逐个替换。
定义ListNode结构体
结构体中应该包含值,以及指向下一个节点的指针
struct ListNode
{
eleType data;
ListNode* next;
ListNode(eleType x) :data(x), next(NULL) {}
};
data用来存储链表中的数据,next是指向下一节点的指针
构造函数 ListNode(eleType x)
初始化了节点的数据成员 data
为传入的参数 x
,并将节点的 next
指针初始化为 NULL
,表示当前节点是链表中的最后一个节点
接下来我们可以根据这个节点结构来创造链表。并实现对链表的增删改查。
定义链表
class LinkedList {
private:
ListNode* head;
int size;
public :
LinkedList():head(NULL),size(0){}
~LinkedList();
void insert(int i, eleType value);
void remove(int i);
ListNode* find(eleType value);
ListNode* get(int i);
void update(int i, eleType value);
void print();
};
私有成员:
- ListNode* head:指向链表头节点的指针
- int size: 表示链表的长度(即节点数量)
公有成员:
- 构造函数
LinkedList()
:初始化链表,将头指针head
设置为NULL
,大小size
设置为0
。 - 析构函数
~LinkedList()
:负责释放链表所占用的内存 插入函数:void insert(int i, eleType value)
:在链表的指定位置i
处插入一个新节点,节点的值为value
。void remove(int i)
:删除链表中指定位置i
处的节点。ListNode* find(eleType value)
:查找链表中是否存在值为value
的节点,如果存在则返回该节点的指针,否则返回NULL
。ListNode* get(int i)
:获取链表中指定位置i
处的节点的指针。void update(int i, eleType value)
:更新链表中指定位置i
处节点的值为value
。void print()
:打印整个链表的内容。
析构函数
LinkedList:: ~LinkedList() {
ListNode* curr = head;
while (curr != NULL) {
ListNode* tmp = curr;
curr = curr->next;
delete tmp;
}
}
注:析构函数(Destructor)是一个特殊的成员函数,它在对象生命周期结束时被调用,用于执行对象资源的清理工作和释放操作。在C++中,析构函数的名称与类名相同,但前面加上一个波浪号(~)作为前缀,没有返回类型,也不接受任何参数。
主要特点包括:
-
命名规则:析构函数的名称由波浪号
~
加上类名组成,如~ClassName
。 -
无参数:析构函数没有参数,因为它只用于对象的销毁,不接受任何外部输入。
-
自动调用:析构函数在对象生命周期结束时自动被调用,无需手动调用。通常发生在对象超出范围、程序结束或者通过
delete
运算符释放动态分配的对象内存时。 -
清理资源:析构函数通常用于释放对象在生命周期中分配的资源,比如释放动态分配的内存、关闭文件、释放网络连接等。
插入函数
void LinkedList::insert(int i, eleType value) {
if (i<0 || i>=size) {
throw std::out_of_range("Invalid position");
}
ListNode* newNode = new ListNode(value);
if (i == 0) {
newNode->next = head;
head = newNode;
}
else {
ListNode* curr = head;
for (int j = 0; j < i - 1; j++) {
curr = curr->next;
}
newNode->next = curr->next;
curr->next = newNode;
}
++size;
}
insert函数接收两个参数,一个是插入位置i,一个是插入的值value。首先我们应该检查插入位置是否合法,如果小于0或者大于链表的size就会抛出异常。
然后我们创造新节点newNode,为其分配内存空间,节点值为value。
如果我们插入的位置是表头,即i为0,将新节点的'next'指针指向原来头结点的'head',并将head指向新节点'newNode',使得新节点成为链表的新头节点。
如果我们插入的位置不是表头,我们遍历链表找到插入位置的前一个结点即第i-1的节点'curr',然后将新节点 newNode
的 next
指针指向当前节点 curr
的下一个节点,将当前节点 curr
的 next
指针指向新节点 newNode
,这样就完成了插入操作。
最后,我们给链表扩容,即++size。
删除函数
void LinkedList::remove(int i) {
if (i<0 || i>=size) {
throw std::out_of_range("Invalid position");
}
if (i == 0) {
ListNode* temp = head;
head = head->next;
delete temp;
}
else {
ListNode* curr = head;
for (int j = 0; j < i - 1; j++) {
curr = curr->next;
}
ListNode* temp = curr->next;
curr->next = temp->next;
delete temp;
}
--size;
}
删除函数接受一个参数:位置i,同样的,我们检查删除位置是否合法。
如果删除头结点的话,首先,创建一个临时指针,指向头节点,然后将头节点指针head指向下一个节点,即删除头节点,最后'delete temp'释放被删除的头结点的内存空间
如果不删除头结点的话,先创建一个指针curr指向头节点,用于遍历链表。然后通过循环找到要删除节点的前一个节点,创建一个临时指针temp,指向要被删除的节点。'curr->next = temp->next;'
:将当前节点的下一个指针指向要删除节点的下一个节点,跳过要删除的节点。最后释放被删除的节点的内存空间。
最后不要忘了size--。
查找函数
ListNode* LinkedList::find(eleType value) {
ListNode* curr = head;
while (curr && curr->data != value) {
curr = curr->next;
}
return curr;
}
用于在链表中查找特定值的节点函数。
find函数:接受一个参数value,表示要查找的结点的值,最后返回一个指向找到的节点的指针
首先创造一个指针curr,并指向链表的头节点,用于遍历整个链表。
while (curr && curr->data != value)
这是一个循环,条件是当前节点指针 curr
不为空且当前节点的值不等于要查找的值。这个循环会一直执行,直到找到节点的值等于要查找的值或者遍历完整个链表。
return curr:返回最终找到的节点的指针。如果找到了值等于 value
的节点,则返回指向该节点的指针;如果遍历完整个链表都没有找到值等于 value
的节点,则返回 nullptr
。
获取节点函数
ListNode* LinkedList::get(int i) {
if (i < 0 || i >= size) {
throw std::out_of_range("Invalid position");
}
ListNode* curr = head;
for (int j = 0; j < i; j++) {
curr = curr->next;
}
return curr;
}
get
函数:接受一个整数参数 i
,表示要获取的节点的位置。函数返回一个指向该位置节点的指针。首先我们应该检查插入位置是否合法,如果小于0或者大于链表的size就会抛出异常。
同样的 我们创建一个指针curr,并指向链表的头节点用于遍历整个链表。for (int j = 0; j < i; j++) { curr = curr->next; }
:这是一个循环,从头节点开始,将 curr
指针移动到要获取的位置 i
处的节点。循环执行 i
次,每次将 curr
指针指向下一个节点,直到达到目标位置
return curr;
:返回指向要获取位置的节点的指针
更新值函数
void LinkedList::update(int i, eleType value) {
get(i)->data = value;
}
update函数:接收整数参数i表示位置,和值value。
在这段代码中,我们首先调用get函数用于获取位置i的结点指针,最后命令他的data等于我们输入的值value
整体代码:
#include<iostream>
#include<stdexcept>
using namespace std;
#define eleType int
struct ListNode
{
eleType data;
ListNode* next;
ListNode(eleType x) :data(x), next(NULL) {}
};
class LinkedList {
private:
ListNode* head;
int size;
public :
LinkedList():head(NULL),size(0){}
~LinkedList();
void insert(int i, eleType value);
void remove(int i);
ListNode* find(eleType value);
ListNode* get(int i);
void update(int i, eleType value);
void print();
};
LinkedList:: ~LinkedList() {
ListNode* curr = head;
while (curr != NULL) {
ListNode* tmp = curr;
curr = curr->next;
delete tmp;
}
}
void LinkedList::insert(int i, eleType value) {
if (i<0 || i>size) {
throw std::out_of_range("Invalid position");
}
ListNode* newNode = new ListNode(value);
if (i == 0) {
newNode->next = head;
head = newNode;
}
else {
ListNode* curr = head;
for (int j = 0; j < i - 1; j++) {
curr = curr->next;
}
newNode->next = curr->next;
curr->next = newNode;
}
++size;
}
void LinkedList::remove(int i) {
if (i<0 || i>=size) {
throw std::out_of_range("Invalid position");
}
if (i == 0) {
ListNode* temp = head;
head = head->next;
delete temp;
}
else {
ListNode* curr = head;
for (int j = 0; j < i - 1; j++) {
curr = curr->next;
}
ListNode* temp = curr->next;
curr->next = temp->next;
delete temp;
}
size--;
}
ListNode* LinkedList::find(eleType value) {
ListNode* curr = head;
while (curr && curr->data != value) {
curr = curr->next;
}
return curr;
}
ListNode* LinkedList::get(int i) {
if (i < 0 || i >= size) {
throw std::out_of_range("Invalid position");
}
ListNode* curr = head;
for (int j = 0; j < i; j++) {
curr = curr->next;
}
return curr;
}
void LinkedList::update(int i, eleType value) {
get(i)->data = value;
}
void LinkedList::print() {
ListNode* curr = head;
while (curr) {
cout << curr->data<<" ";
curr = curr->next;
}
cout << endl;
}
int main() {
LinkedList list;
list.insert(0, 10);
list.insert(1, 20);
list.insert(2, 30);
list.insert(3, 40);
list.insert(4, 50);
list.print();
list.insert(3, 70);
list.print();
list.update(1, 99);
list.print();
list.remove(0);
list.print();
list.find(20);
cout<<list.get(2);
return 0;
}