链表基础理论
名词定义
链表:是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指节点的指针)
**单链表:**只有一个指针域(存放指向下一个节点的指针),最后一个节点的指针指向NULL
**双链表:**有两个指针域(一个指向下一个节点,一个指向上一个节点),头节点的前指针为NULL,尾节点的后指针为NULL;
**循环链表:**链表头尾相连
存储方式
跟数组在内存中的存储有区别,链表的存储在内存中是==不连续分布==的,它是散乱分布在内存中的某个地址上,分配的机制取决于操作系统的内存管理。
对比
插入/删除(时间复杂度) | 查询(时间复杂度) | 使用场景 | |
---|---|---|---|
数组 | O(n) | O(1) | 数据量固定,频繁查询,较少增删 |
链表 | O(1) | O(n) | 数据量不固定,贫富增删,较少查询 |
LeetCode 203.移除链表元素
这道题还是很简单的,只要理解了链表的指针指向,修改前面节点的next指针就行了
正确代码:
/**
* 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* removeElements(ListNode* head, int val) {
if (head == NULL)
{
return NULL;
}
//为链表加一个新的头节点,防止原链表第一个数就是target要删除
ListNode *NewHead = new ListNode();
NewHead->next = head;
ListNode *Node = head; //记录当前节点
ListNode *Pre = NewHead;//记录当前节点的上一个节点
while (Node)
{
if (Node->val == val)
{
ListNode *Tem = Node;
Node = Node->next;
Pre->next = Node;
delete Tem;
}
else
{
Pre = Node;
Node = Node->next;
}
}
return NewHead->next;
}
};
LeetCode 707.设计链表
和上题一样,还是较为基础的题目
正确代码:
class MyLinkedList {
public:
struct LinkNode {
int val;
LinkNode *next;
LinkNode(int n) : val(n), next(NULL)
{}
};
MyLinkedList()
{
Head = new LinkNode(0);
Size = 0;
}
int get(int index)
{
if (index > Size - 1 || index < 0)
{
return -1;
}
LinkNode *P = Head;
for (int i = 0; i < index + 1; i++)
{
P = P->next;
}
return P->val;
}
void addAtHead(int val)
{
LinkNode *Node = new LinkNode(val);
Node->next = Head->next;
Head->next = Node;
Size++;
}
void addAtTail(int val)
{
LinkNode *Node = Head;
while (Node->next)
{
Node = Node->next;
}
LinkNode *NewNode = new LinkNode(val);
Node->next = NewNode;
Size++;
}
void addAtIndex(int index, int val)
{
if (index > Size || index < 0)
{
return;
}
LinkNode *Pre = Head;
LinkNode *Node = Head->next;
for (int i = 0; i < index; i++)
{
Pre = Node;
Node = Node->next;
}
LinkNode *NewNode = new LinkNode(val);
Pre->next = NewNode;
NewNode->next = Node;
Size++;
}
void deleteAtIndex(int index)
{
if (index > Size - 1 || index < 0)
{
return;
}
LinkNode *Pre = Head;
LinkNode *Node = Head->next;
for (int i = 0; i < index; i++)
{
Pre = Node;
Node = Node->next;
}
LinkNode *Tem = Node;
Node = Node->next;
Pre->next = Node;
delete Tem;
Size--;
}
void Dis()
{
LinkNode *P = Head->next;
while (P)
{
cout << P->val << " ";
P = P->next;
}
cout << "End" << endl;
}
private:
LinkNode *Head;
int Size;
};
LeetCode 206.反转链表
这道题只要设置三个节点指针,一个现在节点(Node),一个现在节点的上一个节点(Pre),一个现在节点的下一个节点(Tem),只要把Node的next指针指向Pre,然后再让Node=Tem,Tem向后位移一位就可以了,最后返回的时候记得是返回Pre,因为在跳出循环的时候,Node已经为NULL了。还要注意一下边界问题,避免出现空指针。
正确代码:
/**
* 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)
{
if (head == NULL)
{
return NULL;
}
ListNode *Pre = NULL;
ListNode *Node = head;
ListNode *Tem = Node->next;
while (Node)
{
Tem = Node->next;
Node->next = Pre;
Pre = Node;
Node = Tem;
}
return Pre;
}
};