左程云算法菜手班整理(四)

这篇博客详细介绍了链表的基本操作,包括单链表和双链表的定义,单链表反转,双链表反转,以及如何使用链表实现队列、栈、双端队列。此外,还讲解了如何解决链表相关的复杂问题,如K个节点组内逆序调整和两链表相加。最后,探讨了两个有序链表的合并。这些内容突显了链表在数据结构和算法中的重要性。
摘要由CSDN通过智能技术生成

一.单双链表的定义

struct LinkNode
{
	int data;
	struct LinkNode* node;
};

二.双链表的定义

struct DLNode
{
	int val;
	struct DLNode* next;
	struct DLNode* last;
};

三.反转单链表
逆序之后要把头抓住
代码
注意head引用的传递,java和c++这点是一样的,f(head)内对head的操作是对head的拷贝副本进行的操作,不会改变head。
head直接代表的就是头结点,而不是一个指向头结点的空结点。那样想会把自己弄混。

ListNode* reverseList(ListNode* head) 
{
   ListNode* next=nullptr;
   ListNode* pre=nullptr;
   while(head!=nullptr)
   {
       next=head->next;//记一下head的next的走向,因为要反转
       head->next=pre;
       pre=head;
       head=next;
    }
    return pre;
}

核心是要记住head的下一个位置,用next记住,要不然位置信息会丢失
反转链表的初始状态
反转链表的初始状态
在这里插入图片描述
记一下head的next指针的原始走向,因为要反转
在这里插入图片描述
这里相当于head置空
在这里插入图片描述
pre来到head的位置
在这里插入图片描述
head往下走

四.反转双链表
本质逻辑和反转单链表一样,只不过多了一根last指针要链接

DLNode* reverseDoubleList(DLNode* head)
{
	DLNode* pre = nullptr;
	DLNode* next = nullptr;
	while (head != nullptr)
	{
		next = head->next;//记录下一个位置的信息
		head->next = pre;//链接
		head->last = next;//链接
		pre = head;//为了链接,所以要移位
		head = next;//把head移动到下一个位置,为了循环
	}
	return pre;
}

五.单链表实现队列
直接转载另一个哥们写的,链表主要考察的是coding能力
六.用单链表实现栈;
栈的实现与队的实现相似,而且更简单一些,因为只需要一个栈顶指针

#include<iostream>
using namespace std;

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

template<typename V>
class MyStack
{
private:
	ListNode* head;
	int size;
public:
	MyStack()
	{
		head = nullptr;
		size = 0;
	}
	bool isEmpty()
	{
		return size == 0;
	}
	int size()
	{
		return size;
	}
	void push(V value)
	{
		ListNode* cur = new ListNode(value);
		if (head == nullptr)
		{
			head == cur;
		}
		else 
		{
			cur->next = head;
			head = cur;
		}
		size++;
	}
	V pop()
	{
		V ans = nullptr;
		if (head != null)
		{
			ans = head->val;
			head = head->next;
			size--;
		}
		return ans;
	}
};

七.用双链表实现双端队列
直接转载另一个哥们写的,链表主要考察的是coding能力

八.K个节点组内逆序调整问题(leetcode 第25题 hard)
链表的题,想不明白的话先在纸上推演好流程再写,啥都不清楚写个der。。
这个函数是一个换头函数,肯定不是void类型的
可以先组内逆序,在组间链接,不够一组的直接连接。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) 
    {
        ListNode* start=head;
        ListNode* end=getKGroupEnd(start,k);
        if(end==nullptr)//不够一组的时候这样
        {
            return head;
        }
        //第一组凑齐了
        head=end;//先把头给输出了,因为不管怎么样,结果的链表头一定是这个
        reverse(start,end);
        //上一组的结尾结点
        ListNode* lastEnd=start;
        while(lastEnd->next!=nullptr)
        {
            start=lastEnd->next;
            end=getKGroupEnd(start,k);
            if(end==nullptr)
            {
                return head;
            }
            reverse(start,end);
            lastEnd->next=end;
            lastEnd=start;
        }
        return head;
    }
    ListNode* getKGroupEnd(ListNode* start,int k)
    {
        while(--k!=0&&start!=nullptr)
        {
            start=start->next;
        }
        return start;
    }
    void reverse(ListNode* start,ListNode* end)
    {
        end=end->next;
        ListNode* pre=nullptr;
        ListNode* head=start;
        ListNode* next=nullptr;
        while(head!=end)
        {
            next=head->next;
            head->next=pre;
            pre=head;
            head=next;
        }
        start->next=end;
    }
};

九.两个链表相加问题
给定两个链表的头节点head1和head2,
认为从左到右是某个数字从低位到高位,返回相加之后的链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) 
    {
        int len1=listLength(l1);
        int len2=listLength(l2);
        ListNode* l=len1>=len2?l1:l2;//l为长链表
        ListNode* s=len1>=len2?l2:l1;//s为短链表
        ListNode* curL=l;//初始位置都指向头部
        ListNode* curS=s;//初始位置都指向头部
        ListNode* last=curL;//写入位置
        int carry=0;//进位
        int curNum=0;//当前数据
        while(curS!=nullptr)
        {
            curNum=curL->val+curS->val+carry;
            curL->val = (curNum%10);
            carry=curNum/10;
            last=curL;
            curL=curL->next;
            curS=curS->next;
        }
        while(curL!=nullptr)
        {
            curNum=curL->val+carry;
            curL->val=(curNum%10);
            carry=curNum/10;
            last=curL;
            curL=curL->next;
        }
        if(carry!=0)
        {
            last->next=new ListNode(1);
        }
        return l;
    }
    //求链表长度
    int listLength(ListNode* head)
    {
        int len=0;
        while(head!=nullptr)
        {
            len++;
            head=head->next;
        }
        return len;
    }
};

十.两个有序链表合并

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) 
    {
        if(list1==nullptr||list2==nullptr)
        {
            return list1==nullptr?list2:list1;
        }
        ListNode* head=list1->val<=list2->val?list1:list2;
        ListNode* cur1=head->next;
        ListNode* cur2=list1->val>list2->val?list1:list2;
        ListNode* pre=head;
        
        while(cur1!=nullptr&&cur2!=nullptr)
        {
            if(cur1->val<=cur2->val)
            {
                pre->next=cur1;
                cur1=cur1->next;

            }
            else
            { 
                pre->next=cur2;
                cur2=cur2->next;
            }
            pre=pre->next;
        }
        pre->next=cur1!=nullptr?cur1:cur2;
        return head;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值