算法题-链表

1链表理论基础

1.1什么是链表

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。
链表的入口节点称为链表的头结点也就是head。
链表

1.2链表的类型

单链表

刚刚说的就是单链表。

双链表

单链表中的指针域只能指向节点的下一个节点。
双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。
双链表 既可以向前查询也可以向后查询。
双链表

循环链表

循环链表,顾名思义,就是链表首尾相连。
循环链表可以用来解决约瑟夫环问题。
循环链表

1.3链表的存储方式

了解完链表的类型,再来说一说链表在内存中的存储方式。
数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。
链表是通过指针域的指针链接在内存中各个节点。
所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。
链表的存储方式

1.4链表的定义

  • 定义
// 单链表
struct ListNode {
    int val;  // 节点上存储的元素
    ListNode *next;  // 指向下一个节点的指针
    ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
};
  • 通过自己定义构造函数初始化节点:
ListNode* head = new ListNode(5);
  • 使用默认构造函数初始化节点:
ListNode* head = new ListNode();
head->val = 5;

1.5链表的操作

  • 删除节点

删除节点
只要将C节点的next指针 指向E节点就可以了。
那有同学说了,D节点不是依然存留在内存里么?只不过是没有在这个链表里而已。
是这样的,所以在C++里最好是再手动释放这个D节点,释放这块内存。
其他语言例如Java、Python,就有自己的内存回收机制,就不用自己手动释放了。

  • 添加节点
    添加节点
    可以看出链表的增添和删除都是O(1)操作,也不会影响到其他节点。
    但是要注意,要是删除第五个节点,需要从头节点查找到第四个节点通过next指针进行删除操作,查找的时间复杂度是O(n)。

2相关算法题

2.1移除链表元素

题目
创建虚拟头结点

class Solution 
{
public:
    ListNode* removeElements(ListNode* head, int val) 
    {
        ListNode *vhead = new ListNode(0);
        vhead->next = head;
        ListNode *cur = vhead;
        while(cur->next != NULL)
        {
            if(cur->next->val == val)
            {
                ListNode *temp = cur->next;
                cur->next = cur->next->next;
                delete temp;
            }
            else
            {
                cur = cur->next;
            }
        }
        head = vhead->next;
        delete vhead;
        return head;
    }
};

2.2设计链表(*)

题目

#include <iostream>
using namespace std;

 //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 MyLinkedList {
public:
//初始化链表
    MyLinkedList() {
        _vhead = new ListNode(0);
        _size = 0;
    }
// 获取到第index个节点数值,如果index是非法数值直接返回-1, 注意index是从0开始的,第0个节点就是头结点    
    int get(int index) 
    {
        if (index > (_size - 1) || index < 0)
        {
            return -1;
        }
        ListNode * cur = _vhead->next;
        while(index--)
        {
            cur = cur->next;
        }
        return cur->val;
    }
// 在链表最前面插入一个节点,插入完成后,新插入的节点为链表的新的头结点
    void addAtHead(int val) 
    {
        ListNode * newhead = new ListNode(val);
        newhead->next = _vhead->next;
        _vhead->next = newhead;
        _size++;
    }
// 在链表最后面添加一个节点
    void addAtTail(int val) 
    {
        ListNode * newtail = new ListNode(val);
        ListNode * cur = _vhead;
        while(cur->next != nullptr)
        {
            cur = cur->next;
        }
        cur->next = newtail;
        _size++;

    }
//在第index个节点之前插入一个新节点,index为0,则新插入的节点为头节点
//如果index等于链表长度,新插入节点为尾节点
//index大于链表长度,返回空
//index小于零,头部插入节点
    void addAtIndex(int index, int val) 
    {
        if (index > _size) return;
        if (index < 0) index = 0;
        ListNode * newnode = new ListNode(val);
        ListNode * cur = _vhead;
        while (index--)
        {
            cur = cur->next;
        }
        newnode->next = cur->next;
        cur->next = newnode;
        _size++;
    }
  // 删除第index个节点,如果index 大于等于链表的长度,直接return,注意index是从0开始的   
    void deleteAtIndex(int index) 
    {
        if (index >= _size || index < 0)
        {
            return;
        }
        ListNode * cur = _vhead;
        while(index--)
        {
            cur = cur->next;
        }
        ListNode * tmp = cur->next;
        cur->next = cur->next->next;
        //delete命令指示释放了tmp指针原本所指的那部分内存,
        //被delete后的指针tmp的值(地址)并非就是NULL,而是随机值。也就是被delete后,
        //如果不再加上一句tmp=nullptr,tmp会成为乱指的野指针
        //如果之后的程序不小心使用了tmp,会指向难以预想的内存空间
        delete tmp;

        tmp = nullptr;
        _size--;
    }
            
    void printLinkedList() 
    {
        ListNode * cur = _vhead;
        while (cur->next != nullptr) 
        {
            cout << cur->next->val << " ";
            cur = cur->next;
        }
        cout << endl;
    }

    private :
        int _size;
        ListNode * _vhead;
};

2.3反转链表(*)

题目

#include <iostream>
using namespace std;

 //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* reverseList(ListNode* head) 
    {
        ListNode * pre = NULL;
        ListNode * cur = head;
        ListNode * temp;
        while (cur)
        {
            temp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }
};

2.4两两交换链表中的节点(*)

题目

#include <iostream>
using namespace std;

 //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* swapPairs(ListNode* head) 
    {

        ListNode * vhead = new ListNode(0);
        vhead->next = head;
        ListNode * cur = vhead;
        while (cur->next != nullptr && cur->next->next != nullptr)
        {
            ListNode * temp = cur->next;//存1
            ListNode * temp1 = cur->next->next->next;//存3
            cur->next = cur->next->next;//步骤1
            cur->next->next = temp;//步骤2
            cur->next->next->next = temp1;//步骤3
            cur = cur->next->next; //cur移动两位,准备下一轮交换
        }
        return vhead->next;
    }
};

2.5删除链表的倒数第N个节点

题目

#include <iostream>
using namespace std;

 //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* removeNthFromEnd(ListNode* head, int n) 
    {
        ListNode * vhead = new ListNode(0);
        vhead->next = head;
        ListNode * fast = vhead;
        ListNode * slow = vhead;
        for (int i = 0; i <= n; i++)
        {
            fast = fast->next;
        }
        while (fast != nullptr)
        {
            slow = slow->next;
            fast = fast->next;
        }
        ListNode * temp = slow->next;
        slow->next = slow->next->next;
        delete temp;
        return vhead->next;
    }
}; 

2.6链表相交

题目

#include <iostream>
using namespace std;

 //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 *getIntersectionNode(ListNode *headA, ListNode *headB) 
    {
        int lengthA = linked_list_length(headA);
        int lengthB = linked_list_length(headB);
        if (lengthA >= lengthB)
        return get_intersection_node(headA, headB, lengthA, lengthB);
        else
        return get_intersection_node(headB, headA, lengthB, lengthA);      
    }
private:
    int linked_list_length(ListNode * head)
    {
        int len = 0;
        ListNode * cur = head;
        while (cur != nullptr)
        {
            cur = cur->next;
            len++;
        }
        return len;
    }

    ListNode * get_intersection_node(ListNode *longhead, ListNode *shorthead, int long_len, int short_len)
    {
        int diff = long_len - short_len;
        ListNode * long_cur = longhead;
        ListNode * short_cur = shorthead;
        while (diff--)
        {
            long_cur = long_cur->next;
        }
        while (short_len--)
        {
            if (long_cur == short_cur)
            {
                return long_cur;
            }
            else
            {
                long_cur = long_cur->next;
                short_cur = short_cur->next;
            }
        }
        return nullptr;
    }
};

2.7环形链表(*)

题目
在这里插入图片描述
经推导可得:x = z

#include <iostream>
using namespace std;

struct ListNode
{
    int val;
    ListNode * next;
    ListNode(int x): val(x), next(NULL){}
};
class Solution {
public:
    ListNode *detectCycle(ListNode *head) 
    {
        ListNode * fast = head;
        ListNode * slow = head;
        while (fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
            if (fast == slow)
            {
                ListNode * index2 = fast;
                ListNode * index1 = head;
                while (index1 != index2)
                {
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index1;
            }
        }
        return nullptr;
        
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值