C++ 链表的操作

要求1、将两个有序链表合并成一个链表

思路一
新建一个链表,然后比较两个链表中的元素值,把较小的那个链到新链表中,由于两个输入链表的长度可能不同,所以最终会有一个链表先完成插入所有元素,则直接将另一个未完成的链表直接链入新链表的末尾。

代码实现:

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) 
    {
        ListNode *dummy = new ListNode(-1), *cur = dummy;
        while (l1 && l2) 
        {
            if (l1->val < l2->val) 
            {
                cur->next = l1;
                l1 = l1->next;
            } 
            else 
            {
                cur->next = l2;
                l2 = l2->next;
            }
            cur = cur->next;
        }
        cur->next = l1 ? l1 : l2;
        return dummy->next;
    }
};

下面我们来看递归的写法,当某个链表为空了,就返回另一个。然后核心还是比较当前两个节点值大小,如果l1的小,那么对于l1的下一个节点和l2调用递归函数,将返回值赋值给l1.next,然后返回l1;否则就对于l2的下一个节点和l1调用递归函数,将返回值赋值给l2.next,然后返回l2

代码实现

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) 
    {
        if (!l1) return l2;
        if (!l2) return l1;
        if (l1->val < l2->val) 
        {
            l1->next = mergeTwoLists(l1->next, l2);
            return l1;
        } 
        else 
        {
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};

下面这种递归的写法去掉了if从句,看起来更加简洁一些,但是思路并没有什么不同:

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) 
    {
        if (!l1) return l2;
        if (!l2) return l1;
        ListNode *head = l1->val < l2->val ? l1 : l2;
        ListNode *nonhead = l1->val < l2->val ? l2 : l1;
        head->next = mergeTwoLists(head->next, nonhead);
        return head;
    }
};

还可以三行搞定,简直丧心病狂有木有!

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) 
    {
        if (!l1 || (l2 && l1->val > l2->val)) swap(l1, l2);
        if (l1) l1->next = mergeTwoLists(l1->next, l2);
        return l1;
    }
};

思路二
首先,将两个链表直接合并成一个链表(未经排序的,直接链表1的尾节点指向链表2的第一个结点,当然这两者都是不带头结点的链表),然后,对链表中节点的元素进行排序就行啦,最小的节点值放在第一个节点里,以此类推。则可以实现两个有序链表合并成一个有序链表的目的。

要求二、要求将一个链表逆序

思路一
头插法,改变结构。从第二个结点开始往后,依次把每个结点移至链表头部,要注意最后链表不要是断裂的.
代码实现:

ListNode *ReverseList1(ListNode *pHead)//头插法(改变链表结构)
{
	if(pHead==NULL)
		return NULL;
	ListNode *p=pHead->next;
	ListNode *newHead=pHead;
	while(p!=NULL)
	{//将p结点移到链表最前方
		pHead->next=p->next;//头结点指向p的下一个结点
		p->next=newHead;	//p插入链表最前方
		newHead=p;		//链表新头结点更新为p
		p=pHead->next;//处理下一个结点,该结点位于头结点后
	}
	return newHead;
}

思路二
只逆序打印,不改变结构。利用栈的后进先出来实现逆序。
代码实现:

void printListFromTailToHead(ListNode *pHead)
{
	stack<ListNode*> nodes;
	ListNode *p=pHead;
	while(p!=NULL)
	{
		nodes.push(p);//入栈
		p=p->next;
	}
	while(!nodes.empty())
	{
		p=nodes.top();//赋值
		cout<<p->val<<endl;
		nodes.pop();//删除栈顶元素
	}
}

要求三、判断一个链表是否有环?

思路:
如果一个单链表中有环,用一个指针去遍历,永远不会结束,所以可以用两个指针,一个指针一次走一步,另一个指针一次走两步,如果存在环,则这两个指针会在环内相遇,时间复杂度为O(n)。
代码实现:

struct ListNode
{
    int key;
    ListNode * next;
};

bool HasCircle(ListNode * pHead)
{
    ListNode * pFast = pHead; // 快指针每次前进两步
    ListNode * pSlow = pHead; // 慢指针每次前进一步
    while(pFast != NULL && pFast->next != NULL)
    {
        pFast = pFast->next->next;
        pSlow = pSlow->next;
        if(pSlow == pFast) // 相遇,存在环
            return true;
    }
    return false;
}
拓展问题A:如果单链表有环,找出环的入口节点(环的连接点)

思路:
假设单链表的总长度为L,头结点到环入口的距离为a,环入口到快慢指针相遇的结点距离为x,环的长度为r,慢指针总共走了s步,则快指针走了2s步。另外,快指针要追上慢指针的话快指针至少要在环里面转了一圈多(假设转了n圈加x的距离),得到以下关系:
s = a + x
2s = a + nr + x
=>a + x = nr
=>a = nr - x

由上式可知:若在头结点和相遇结点分别设一指针,同步(单步)前进,则最后一定相遇在环入口结点。

代码实现:

ListNode * FindLoopPort(ListNode *head)  
{  
    ListNode *slow = head, *fast = head;    
    while ( fast && fast->next )   
    {  
        slow = slow->next;  
        fast = fast->next->next;  
        if ( slow == fast ) break;  
    }    
    if (fast == NULL || fast->next == NULL)  
        return NULL;  
    slow = head;  
    while (slow != fast)  
    {  
         slow = slow->next;  
         fast = fast->next;  
    }  
    return slow;  
} 

拓展问题B:求环的长度。

思路:
让指针指向入口节点,遍历直到回到入口节点,走过的长度即环的长度。
代码实现:

//求单链表环的长度
int circleLength(ListNode L)
{
    ListNode p=searchEntranceNode(L);//找到环的入口结点
    if(p==null) return 0;//不存在环时,返回0
    ListNode q=p.next;
    int length=1;
    while(p!=q)
    {
       length++;
       q=q.next;
    }
    return length;//返回环的长度
}

转自:https://www.cnblogs.com/ghimtim/p/4882916.html

猜你喜欢

转载自blog.csdn.net/QIJINGBO123/article/details/88396587
今日推荐