链表理论
链表类型
-
单链表
-
双链表:每个节点有两个指针域,一个指向下一个节点,一个指向上一个节点
既可以查询前一个节点,又能查询后一个节点 -
循环列表:链表首尾相连
链表的存储方式
在内存上不是连续分布的,散乱分布在内存中的某地址上
链表的定义
// 单链表
struct ListNode {
int val; // 节点上存储的元素
ListNode *next; // 指向下一个节点的指针
ListNode(int x) : val(x), next(NULL) {} // 节点的构造函数
};
链表的操作
-
删除节点:next指针直接指向下下个节点,且在内存中删除要移除的节点
-
添加节点:
203.移除链表元素
要点:虚拟头节点,为了避免要删除的节点是头结点,虚拟头结点可以统一写法
如何遍历:
cur->next != NULL
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
dummyHead->next = head; // 将虚拟头结点指向head,这样方面后面做删除操作
ListNode* cur = dummyHead;
while (cur->next != NULL) {//cur指针最后只能停在倒数第二个节点
if(cur->next->val == val) {
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;//有tmp才能删掉
} else {
cur = cur->next;
}
}
head = dummyHead->next;
delete dummyHead;
return head;
}
};
注意:如果找不到等于目标值的节点,那么cur指针一直移动,直到指到倒数第二个节点,并且最后操作移动到最后一个节点,注意循环的条件
707.设计链表
思路:
注意:假设链表中的所有节点下标从 0 开始。
- 定义一个单链表
struct LinkedNode {
int val;
LinkedNode* next;
LinkedNode(int val):val(val), next(nullptr){}
};
- 获取到第index个节点数值,如果index是非法数值直接返回-1
cur指针从头结点开始,因为头节点下标是从0开始的,所以是第几个节点就移动几次
int get(int index) {
if (index > (_size - 1) || index < 0) {
return -1;
}
LinkedNode* cur = _dummyHead->next;
while(index--){ // 如果--index 就会陷入死循环
cur = cur->next;
}
return cur->val;
}
- 在链表最前面插入一个节点,插入完成后,新插入的节点为链表的新的头结点
void addAtHead(int val) {
LinkedNode* newNode = new LinkedNode(val);
newNode->next = _dummyHead->next;
_dummyHead->next = newNode;
_size++;
}
- 在链表最后面添加一个节点
让cur指针从虚拟头结点,一直移动到最末节点位置,然后其下一个节点就是新加入的节点
void addAtTail(int val) {
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead;
while(cur->next != nullptr){
cur = cur->next;
}
cur->next = newNode;
_size++;
}
- 在第index个节点之前插入一个新节点
要点:分情况讨论
让cur指向虚拟头几点,是第几个节点,让cur指针移动到前一个节点位置,再连接新节点
void addAtIndex(int index, int val) {
if(index > _size) return;
if(index < 0) index = 0;
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead;
while(index--) {
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
_size++;
}
- 打印链表
void printLinkedList() {
LinkedNode* cur = _dummyHead;
while (cur->next != nullptr) {
cout << cur->next->val << " ";
cur = cur->next;
}
cout << endl;
}
206.反转链表
思路:
用两个指针,cur指针最初指向头结点,pre指针指向虚拟头结点,即为空。始终保持前后关系,这样就可以连接前后节点
定义tmp节点的目的是,保存后一个节点,因为已经改变了连接顺序,不能再通过cur->next来查找后一个节点,所以需要事先保存
循环结束的条件是cur指针移动到了最后一个节点处,此时完成最后一个节点的连接,文章来源:https://www.toymoban.com/news/detail-440733.html
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* tmp;
ListNode* cur=head;
ListNode* pre=NULL;
while(cur!=NULL){
tmp=cur->next;
cur->next=pre;
pre=cur;
cur=tmp;
}
return pre;
}
};
递归法仍然不太会写文章来源地址https://www.toymoban.com/news/detail-440733.html
到了这里,关于day3-链表理论基础 203.移除链表元素 707.设计链表 206.反转链表的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!