【一周编程学习】--2.单链表与环形链表的实现

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链表是否存在环,如果存在,则两个链表相交,而检测出来的依赖环入口即为相交的第一个点。
  • 求有序链表中求出其中位数,这种问题也是设置快慢指针,当快指针到底链表尾部的时候,慢指针刚好指向链表中间的结点。
     

猜你喜欢

转载自blog.csdn.net/wxq_1993/article/details/85783017