1.单链表知识小结
- 构成:头指针(Header),若干个节点(节点包括了数据域和指针域),最后一个节点要指向空。
- 单链表的基本操作初始化:
typedef int ElemType;
typedef struct Node{
ElemType data;
struct Node* next;
}Node;
typedef struct Node* LinkList;
void initList(LinkList *L){
(*L)=(LinkList)malloc(sizeof(Node));
(*L)->next=NULL;
(*L)->data=0;}
- 单链表的插入:
s=(LinkList)malloc(sizeof(Node));
s->data=e;
s->next=p->next;
p->next=s;
- 单链表的删除:
q=p-next;
p->next=q->next;
*e=q->data;
free(q);
- LinkList L、LinkList *L、Node *p、Node p的用法:
LinkList L: L是指向定义的node结构体的指针,
LinkList *L:L是指向定义的Node结构体指针的指针,用头指针表示链表类,即实质是该链表的头指针类型
Node *p :定义了一个node类型的结构体指针p,p是工作指针(初始时p指向)
Node p:在网上到时没有查到Node p的使用,不过倒是查到了P=new node()的使用,也表示node类型的指针
如果函数会改变指针L的值,而你希望函数结束调用后保存L的值,那你就要用LinkList *L,这样,向函数传递的就是指针的地址,结束调用后,自然就可以去改变指针的值;而如果函数只会修改指针所指向的内容,而不会更改指针的值,那么用LinkList L就行了;
2.LeetCode第206题 单链表的翻转
单链表的反转是对结点一个一个操作的,每次把后面的一个结点抛到前面,不需要开辟另外的内存空间。
使用C++和Python实现:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==NULL)
return NULL;
//结点初始化
ListNode *pCur,*pPre,*pNext;
pPre=head;
pCur=pPre->next;
//翻转链表
while(pCur){
pNext=pCur->next;
pCur->next=pPre;
pPre=pCur;
pCur=pNext;
}
//返回头指针
head->next=NULL;
head=pPre;
return head;
}
};
class Solution:
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if head is None:
return None
p=head
pCur=None
pPre=None
while p is not None:
pCur=p.next
p.next=pPre
pPre=p
p=pCur
return pPre
3. LeetCode 第142题 环形链表
- 方法一:快慢指针法
判断一个单链表是否有环的问题。如果一个单向链表不带环,那尾部结点的next指针是NULL,否则尾结点的指针指向链表中的某一结点的数据域。通常可采用快慢指针,定义两个指针,一个指针一次移动一个结点slowP,另一个指针一次移动两个结点fastP,如果两个指针相遇,那么是有环;否则快指针指向NULL,则是无环;第一次相遇时,slowP指向头结点,fastP指向相遇的结点处,每次移动一个结点,直到再次相遇,得到位置。
使用C++和Python实现:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head==NULL||head->next==NULL)
return NULL;
ListNode* fastP=head;
ListNode* slowP=head;
while(slowP!=NULL&&fastP!=NULL&&fastP->next!=NULL)
{
slowP=slowP->next;
fastP=fastP->next->next;
if(slowP==fastP)
{
ListNode *slowP1=head;
while(slowP1!=slowP)
{
slowP=slowP->next;
slowP1=slowP1->next;
}
return slowP;
}
}
return NULL;
}
};
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
slow,fast=head,head
while fast and fast.next:
slow=slow.next
fast=fast.next.next
if slow==fast:
slow=head
while fast!=slow:
fast=fast.next
slow=slow.next
return slow
- 方法二:哈希解法
使用unordered_map记录当前节点是否被访问过,如访问过返回该节点,如到达尾部说明无环。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
unordered_map<ListNode*,bool> visited;
while(head!=NULL)
{
if(visited[head]==true)
return head;
visited[head]=true;
head=head->next;
}
return NULL;
}
};
快慢指针的应用:
- 判断一个链表是否有环
- 求一个链表是否存在环,如果存在,则求出环的入口结点
- 另一个应用是求链表是否存在环的变式,如给定两个链表A和B,判断两个链表是否相交,解决方法就是将A链表尾节点指向头结点形成一个环,检测B链表是否存在环,如果存在,则两个链表相交,而检测出来的依赖环入口即为相交的第一个点。
- 求有序链表中求出其中位数,这种问题也是设置快慢指针,当快指针到底链表尾部的时候,慢指针刚好指向链表中间的结点。