1.顺序表和链表的优缺点以及适应场景
顺序表支持随机访问,而单链表不支持随机访问;
顺序表插入/删除数据效率很低,时间复杂度为O(N)(除尾插尾删),单链表插入/删除效率更高,时间复杂度为O(1)。
-
顺序表的CPU高速缓存效率更高,单链表CPU高速缓存效率低。
-
适用场景:
-
频繁的查找却很少的插入和删除操作可以用顺序表存储,如果频繁的插入和删除操作很少的查询就可以使用链表存储。
2.逆置单链表
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead)
{
if(pHead==NULL||pHead->next==NULL)
return pHead;
ListNode* newpHead=pHead;
pHead=pHead->next;
newpHead->next=NULL;
ListNode* cur=NULL;
while(pHead!=NULL)
{
cur=pHead;
pHead=pHead->next;
cur->next=newpHead;
newpHead=cur;
}
pHead=newpHead;
return pHead;
}
};
3.从尾到头打印单链表
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<ListNode*> v;
ListNode* cur=head;
while(cur!=NULL){
v.push_back(cur);
cur=cur->next;
}
int countNode=v.size();
vector<int> rList;
for(int i=countNode-1;i>=0;i--){
rList.push_back(v[i]->val);
}
return rList;
}
};
递归版(一般从尾到头都可以转化为递归和非递归两个版本)
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head)
{
vector<int> v;
_printListFromTailToHead(head,v);
return v;
}
void _printListFromTailToHead(ListNode* head,vector<int>& v)
{
if(head==NULL)
return ;
_printListFromTailToHead(head->next,v);
v.push_back(head->val);
return ;
}
};
4.删除无头单链表的非尾结点
//采用的替换值的方法去删除它的下一个结点(找个替身)
void RemoveNodeWired(Node* node)
{
if (node->_next == NULL || node == NULL)
return; //证明为尾结点或者当前结点为空
Node* del = node->_next;
swap(del->_value, node->_value); //将当前结点的值和要删除结点的值交换
node->_next = del->_next;
del->_next = NULL;
delete del;
}
5.判断两个链表是否相交(不带环)
Node* ListIntersect(Node* pHead1, Node* pHead2)
{
if (pHead1 == pHead2) //头结点一样
return pHead1;
if (pHead1 == NULL || pHead2 == NULL)
return NULL;
stack<Node*> s1; //保存链表1的结点
stack<Node*> s2; //保存链表2的结点
Node* cur = pHead1;
while (cur != NULL)
{
s1.push(cur);
cur = cur->_next;
}
cur = pHead2;
while (cur != NULL)
{
s2.push(cur);
cur = cur->_next;
}
if (s1.top() != s2.top()) //尾结点不一样
{
return NULL;
}
//链表一定有相交结点,且不为头结点
Node* prev = NULL;
while (s1.top()==s2.top())
{
prev = s1.top();
s1.pop();
s2.pop();
}
return prev;
}
6.判断一个链表是否带环,并且返回环的长度
//返回环的长度和环的入口结点
pair<ListNode*,int> EntryNodeOfLoop(ListNode* pHead)
{
Node* slow = pHead;
Node* fast = pHead;
Node* None = NULL;
int count = 0;
while (slow != NULL && fast->_next != NULL)
{
//利用快慢指针判环
slow = slow->_next;
fast = fast->_next->_next;
if (fast == slow) //证明有环
{
//将快慢指针任意一个从头结点开始走,二者按一步一节点的速度相遇就是环的入口点
slow = pHead;
while (slow != fast)
{
slow = slow->_next;
fast = fast->_next;
}
while (slow->_next != fast)
{
count++;
slow = slow->_next;
}
return make_pair(fast, count + 1);
}
}
return make_pair(None,0);
}
7.判断两个链表是否相交?相交求交点(可能带环)
Node* ListIntersectHasRing(Node* pHead1, Node* pHead2)
{
if (pHead1 == pHead2) //头结点一样
return pHead1;
if (pHead1 == NULL || pHead2 == NULL)
return NULL;
pair<Node*, int> RingNode1 = EntryNodeOfLoop(pHead1); //entryNodeOfLoop用来判环的入口点
pair<Node*, int> RingNode2 = EntryNodeOfLoop(pHead2);
if (RingNode1.first == NULL&&RingNode2.first == NULL) //证明两个链表不带环
return ListIntersect(pHead1, pHead2);
if ((RingNode1.first == NULL&&RingNode2.first != NULL) ||
(RingNode1.first != NULL&&RingNode2.first == NULL)) //一个带环一个不带环
return NULL;
//两个都带环
Node* cur = pHead1;
//是同一个环环的入口点一样但是交点可能在到环的入口点的路上
if (RingNode1.first == RingNode2.first) //环的入口点一样的
{
stack<Node*> s1;
stack<Node*> s2;
while (cur != RingNode1.first->_next) //可能交点就为环入口,所以要到下一个结点
{
s1.push(cur);
cur = cur->_next;
}
cur = pHead2;
while (cur != RingNode2.first->_next)
{
s2.push(cur);
cur = cur->_next;
}
Node* prev = NULL;
while (!s1.empty() && !s2.empty() && s1.top() == s2.top())
{
prev = s1.top();
s1.pop();
s2.pop();
}
return prev;
}
//判断是不是同一个环
int count = 0; //count用来记录cur经过RingNode环入口点的次数
cur = pHead1;
while (count!= 2) //经过自身的环入口点超过两次,证明两个在不同的环上
{
if (cur==RingNode1.first) //证明经过自身的环入口点
{
count++;
}
if (cur == RingNode2.first) //证明在同一个环上,随便返回环的哪一个入口点都可
{
return RingNode2.first;
}
cur = cur->_next;
}
return NULL;
}
8.复杂链表的复制
struct RandomListNode
{
int label;
struct RandomListNode *next, *random;
RandomListNode(int x)
:label(x)
, next(NULL)
, random(NULL)
{}
};
class Solution {
public:
typedef RandomListNode Node;
RandomListNode* Clone(RandomListNode* pHead)
{
if (pHead == NULL)
return NULL;
Node* cur = pHead->next;
Node* newHead = new Node(pHead->label);
Node* newCur = newHead;
vector<Node*> Random;
vector<Node*> NewList;
NewList.push_back(newHead);
Random.push_back(pHead->random);
while (cur != NULL)
{
Random.push_back(cur->random);
Node* newNode = new Node(cur->label);
newCur->next = newNode;
newCur = newNode;
NewList.push_back(newNode);
cur = cur->next;
}
vector<int> RandomPosition;
int count = 0;
for (size_t i = 0; i < Random.size(); i++)
{
cur = pHead;
count = 0;
if (Random[i] == NULL)
{
RandomPosition.push_back(-1);
}
else
{
while (cur != NULL)
{
if (cur == Random[i])
{
RandomPosition.push_back(count);
break;
}
cur = cur->next;
count++;
}
}
}
for (size_t i = 0; i < NewList.size(); i++)
{
if (RandomPosition[i] == -1)
{
NewList[i]->random = NULL;
}
else
{
NewList[i]->random = NewList[RandomPosition[i]];
}
}
return newHead;
}
};