一、链表的定义
链表是一种动态数据结果,内存分配不是在创建链表时一次性完成的,每添加一个节点,分配一次内存,由于没有闲置的内存,链表的空间效率高于数组
二、定义单向链表
struct ListNode
{
int m_nValue;
ListNode* m_pNext;
};
void AddToTail(ListNode** pHead, int value)
{
ListNode* pNew = new listNode();
pNew->m_nValue = value;
pNew->m_pNext = nullptr;
if (*pHead == nullptr)
{
*pHead = pNew;
}
else
{
ListNode* pNode = *pHead;
while (*pHead->m_pNext != nullptr)
pNode = pNode->m_pNext;
pNode->m_pNext = pNew;
}
}
3. 删除链表中的一个元素
void RemoveNode(ListNode** pHead, int value)
{
if (pHead == nullptr || *pHead == nullptr)//pHead是指向链表头节点的指针,*pHead是链表的头节点
return;
ListNode* pToBeDeleted = nullptr;
//分成两种情况,头节点和其他节点
if ((*pHead)->m_nValue == value)//如果头节点是要删除的目标
{
pToBeDeleted = *pHead;
*pHead = (*pHead)->m_pNext;
}
else
{
ListNode* pNode = *pHead;
while (pNode->m_pNext != nullptr && pNode->m_pNext->m_nValue != value)
pNode = pNode->m_pNext;
if (pNode->m_pNext != nullptr && pNode->m_pNext->m_nValue == value)
{
pToBeDeleted = pNode->m_pNext;
pNode->m_pNext = pNode->m_pNext->m_pNext;
}
}
if (pToBeDeleted != nullptr)
{
delete pToBeDeleted;
pToBeDeleted = nullptr;
}
}
4 从头到尾打印链表
- 上面这段代码中设计到了结构体的知识,结构体以struct为关键字,结构体内部可以有多个变量和函数。结构体的定义结构如下
struct Person
{
int n_year;
string name;
void sayHellow()
{
定义内容;
}
};
- ListNode** pHead
两个**表示的是指向指针的指针
5 相交链表
5.1方法一
使用哈希表解决
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
unordered_set<ListNode *> visited;
ListNode *temp = headA;
while (temp != nullptr){
visited.insert(temp);
temp = temp->next;
}
temp = headB;
while (temp != nullptr){
if(visited.count(temp)){
return temp;
}
temp = temp->next;
}
return nullptr;
}
};
5.1.2代码中遇到的问题
1.哈希表的定义
unordered_set 无键值哈希表
unordered_map 有键值哈希表
2.哈希表的一些函数
1.插入元素:
insert(key, value):向std::unordered_map中插入键值对(key, value)。
insert(value):向std::unordered_set中插入元素value。
2.访问元素:
at(key):以给定的key作为参数,在std::unordered_map中查找对应的值,并返回引用。
find(key):在std::unordered_map中查找具有给定key的元素。如果找到,返回指向该元素的
迭代器;否则返回end()迭代器。
count(key):在std::unordered_map中计算具有给定key的元素个数。当存在时,返回1,否则返回0。
3.删除元素:
erase(key):从std::unordered_map中删除具有给定key的键值对。
erase(position):从std::unordered_map或std::unordered_set中删除给定位置(迭代器)上的元素。
clear():从std::unordered_map或std::unordered_set中删除所有元素。
4.迭代遍历:
使用auto关键字和range-based for循环遍历哈希表中的元素。
使用迭代器(如begin()和end())进行循环访问。
5.2方法二
使用双指法,双指针法的时间复杂度为O(n),空间复杂度为O(1)
class Solution{
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)
{
ListNode *A = headA;
ListNode *B = headB;
while (A!=nullptr && B!=nullptr)
{
A = A->next;
B= B->next;
}
if (A ==nullptr) A = headB;
if (B ==nullptr) B = headA;
while (A!=nullptr && B!=nullptr)
{
A = A->next;
B= B->next;
}
if (A ==nullptr) A = headB;
if (B ==nullptr) B = headA;
while (A!=nullptr && B!=nullptr)
{
if(A == B) return A;
A = A->next;
B= B->next;
}
return nullptr;
}
};
5.2.1 遇到的问题
nullptr:在C++中,nullptr 是一个特殊的空指针常量,用于表示一个指针不指向任何有效的内存地址。它在C++11标准中引入,旨在取代以前使用的 NULL 或 0 来表示空指针
6.删除链表倒数第n个节点
题目:
6.1 方法一
运行两遍,第一遍读取链表长度,第二遍删除节点
class Solution{
public:
ListNode* removeNthFromEnd(ListNode* head, int n){
if (head==nullptr||head->next==nullptr) return nullptr;
ListNode* A = head;
int sum_count=0;
while(A!=nullptr)
{
A = A->next;
sum_count = sum_count + 1;
}
int forward_count = sum_count - n;
A = head;
if(n==1)//删除尾节点
{
while (sum_count-->2)
{
A = A->next;
}
ListNode* B = A->next;
A->next = nullptr;
delete B;
}
else if(sum_count==n)//删除头节点
{
ListNode* B = A;
head = head->next;
delete B;
}
else//删除中间节点
{
while (forward_count-->1)
{
A = A->next;
}
ListNode* B = A->next;
A->next = A->next->next;
delete B;
}
return head;
}
};
6.2 方法二
使用栈的形式,先入栈,然后弹栈,弹的第N个,即为要删除的节点
class Solution{//栈的形式找节点
public:
ListNode* removeNthFromEnd(ListNode* head, int n){
stack<ListNode*> stk;
ListNode* dummy = new ListNode(0,head);
ListNode *A = head;
ListNode *B = dummy;
while(dummy)
{
stk.push(dummy);
dummy = dummy->next;
}
while(n-->0)
{
stk.pop();
}
ListNode *prev = stk.top();
A = prev->next;
prev->next = prev->next->next;
delete A;
head = B->next;
delete dummy;
return head;
}
};
6.2.1 遇到的问题
栈的定义:
栈的定义使用std模板中的stack,stack中有一些函数
入栈:stk.push(dummy);
出栈:stk.pop();
读取栈顶元素:stk.top();
方法三 6.3
快慢指针
class Solution{//快慢指针
public:
ListNode* removeNthFromEnd(ListNode* head, int n){
ListNode* dummy = new ListNode(0, head);
ListNode* Fast = head;
ListNode* Low = dummy;
for(int i = 0; i < n; ++i)
{
Fast = Fast->next;
}
while(Fast)
{
Fast = Fast->next;
Low = Low->next;
}
Low->next = Low->next->next;
ListNode* ans = dummy->next;
delete dummy;
return ans;
}
};