为什么有链表:数组很棒,但是插入和删除时需要移动大量的元素,消耗时间。在第一个位置插入元素时后面的元素都要向后移动
链表的基本思维:利用结构体的设置,额外开辟出一份内存空间去作指针,它总是指向下一个结点,一个个结点通过NEXT指针相互串联,就形成了链表。
一个是自己的数据,另外一个是指针指向下一个数据所在的位置。
插入新值后,
下面是实现单链表的实例
#include
// 定义链表节点结构
struct Node {
int data; // 数据部分
Node* next; // 指针部分,指向下一个节点的位置
};
class LinkedList {
private:
Node* head; // 头节点指针,指向链表的第一个节点
public:
// 构造函数
LinkedList() {
head = nullptr; // 初始化头节点为空
}
// 在链表尾部插入新节点
void append(int value) {
Node* newNode = new Node; // 创建新节点
newNode->data = value; // 设置新节点的数据
newNode->next = nullptr; // 新节点的next指针指向空值
if (head == nullptr) {
head = newNode; // 如果链表为空,直接将新节点设置为头节点
} else {
Node* current = head;//如果不为空,从头节点找最后节点
while (current->next != nullptr) {
current = current->next; // 找到链表最后一个节点
}
current->next = newNode; // 将新节点连接到最后一个节点后面
}
}
// 删除链表中指定数值的节点
void remove(int value) {
if (head == nullptr) {//链表是空,就提示
std::cout << "Empty list. Nothing to remove." << std::endl;
return;
}
if (head->data == value) {//这个值是头节点就删除
Node* temp = head;
head = head->next;
delete temp;
return;
}
Node* current = head;
while (current->next != nullptr) {//遍历节点
if (current->next->data == value) {
Node* temp = current->next;
current->next = current->next->next;
delete temp;
return;
}
current = current->next;
}
std::cout << "Value " << value << " not found in the list." << std::endl;
}
// 打印链表元素
void print() {
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " ";
current = current->next;
}
std::cout << std::endl;
}
//指定·位置插入数值
void insertAt(int value, int position) {
Node* newNode = new Node; // 创建新节点
newNode->data = value; // 设置新节点的数据
if (position == 0) {
newNode->next = head; // 将新节点的next指针指向当前的头节点
head = newNode; // 更新头节点为新节点
return;
}
// 寻找要插入位置的前一个节点
Node* current = head;
for (int i = 0; i < position - 1 && current != nullptr; i++) {
current = current->next;
}
if (current == nullptr) {
std::cout << "Invalid position." << std::endl;
return;
}
newNode->next = current->next; // 将新节点的next指针指向当前节点的next节点
current->next = newNode; // 将当前节点的next指针指向新节点
}
};
int main() {
LinkedList list;
list.insert(5);
list.insert(10);
list.insert(15);
list.print(); // 输出:5 10 15
list.remove(10);
list.print(); // 输出:5 15
return 0;
}
```
单链表删除节点操作
LinkedList LinkedListDelete(LinkedList L,int x) {
Node *p,*pre; //pre为前驱结点,p为查找的结点。
p = L->next;//下一个节点
while(p->data != x) { //查找值为x的元素
pre = p;
p = p->next;//没有就下一个
}
pre->next = p->next; //删除操作,将其前驱next指向其后继。
free(p);//释放地址
return L;
}
链表主要注意元素的next指向位置,没有在第几个这个概念,删除的原理换成python写比较清楚一些,思维方面需要转变。一般通过循环找到响应的位置进行删除。
class ListNode:
def init(self, val=0, next=None):
self.val = val
self.next = next
def deleteAtIndex(head, index):
# 处理删除头节点的情况
if index == 0:
return head.next
prev = None
curr = head
# 遍历链表,找到目标位置的节点
while curr and index > 0:
prev = curr
curr = curr.next
index -= 1
# 如果链表长度不足,无法删除节点
if index > 0:
return head
prev.next = curr.next # 跳过 curr 节点,将 prev 的 next 指向 curr 的下一个节点
curr.next = None # 释放 curr 节点的内存空间
return head
创建链表 1 -> 2 -> 3 -> 4 -> 5
head = ListNode(1)
node2 = ListNode(2)
node3 = ListNode(3)
node4 = ListNode(4)
node5 = ListNode(5)
head.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
删除第3个节点
head = deleteAtIndex(head, 2)
打印链表
curr = head
while curr:
print(curr.val, end=" -> ")
curr = curr.next
```
输出结果为:
1 -> 2 -> 4 -> 5 ->
一些力扣题:(一)实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。
/**遍历链表并统计链表长度,记链表长度为 N;
设置一个节点指针向前走 N−k步,便可找到链表倒数第 k 个节点
初始化双指针 pre , cur 都指向头节点 head ;
先令 cur 走 k 步,此时 pre , cur 的距离为 k ;
令 pre , cur 一起走,直到 cur 走过尾节点时跳出,此时 pre 指向「倒数第 k个节点」,返回之即可;
(不知道链表的末尾在,也不知道在具体哪个位置)
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
int kthToLast(ListNode* head, int k) {
ListNode *pre = head, *cur = head;
for (int i = 0; i < k; i++)//建立循环,一直数下去
cur = cur->next;//cur先走k步
while (cur != nullptr) {
pre = pre->next;
cur = cur->next;//cur和pre一起走,cur到末尾,pre到达倒数第k个
}
return pre->val;
}
};
(二)若链表中的某个节点,既不是链表头节点,也不是链表尾节点,则称其为该链表的「中间节点」。假定已知链表的某一个中间节点,请实现一种算法,将该节点从链表中删除。
class Solution {
public:
void deleteNode(ListNode* node) {
node->val = node->next->val;
node->next = node->next->next;
}
};