c++中单向链表的代码实现

 

#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++中,析构函数的名称与类名相同,但前面加上一个波浪号(~)作为前缀,没有返回类型,也不接受任何参数。

主要特点包括:

  1. 命名规则:析构函数的名称由波浪号 ~ 加上类名组成,如 ~ClassName

  2. 无参数:析构函数没有参数,因为它只用于对象的销毁,不接受任何外部输入。

  3. 自动调用:析构函数在对象生命周期结束时自动被调用,无需手动调用。通常发生在对象超出范围、程序结束或者通过 delete 运算符释放动态分配的对象内存时。

  4. 清理资源:析构函数通常用于释放对象在生命周期中分配的资源,比如释放动态分配的内存、关闭文件、释放网络连接等。

插入函数

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',然后将新节点 newNodenext 指针指向当前节点 curr 的下一个节点,将当前节点 currnext 指针指向新节点 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;
}

在Java单向链表是一种常见的数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。单向链表的特点是只能从头节点开始遍历到尾节点,不能反向遍历。 下面是一个简单的Java实现单向链表的例子: ```java public class Node { int data; // 节点数据 Node next; // 指向下一个节点的指针 public Node(int data) { this.data = data; this.next = null; } } public class LinkedList { Node head; // 链表头节点 public LinkedList() { this.head = null; } // 在链表尾部添加节点 public void add(int data) { Node newNode = new Node(data); if (head == null) { head = newNode; } else { Node current = head; while (current.next != null) { current = current.next; } current.next = newNode; } } // 在链表查找某个节点是否存在 public boolean contains(int data) { Node current = head; while (current != null) { if (current.data == data) { return true; } current = current.next; } return false; } // 删除链表第一个出现的指定节点 public void remove(int data) { if (head == null) { return; } if (head.data == data) { head = head.next; return; } Node current = head; while (current.next != null) { if (current.next.data == data) { current.next = current.next.next; return; } current = current.next; } } // 获取链表的节点数 public int size() { int count = 0; Node current = head; while (current != null) { count++; current = current.next; } return count; } } ``` 在上面的代码Node类表示链表节点,LinkedList类表示单向链表。它包含了添加、查找、删除和获取节点数等常见操作。你可以根据自己的实际需求来对链表进行操作。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值