数据结构,单链表及一些题目

数据结构中,一个常用的数据结构--链表。    链表的种类主要为:单链表双链表循环链表。

1、单链表的定义

  • 课本上所学,单链表。(复习一下 typedef ,节点变量,指针变量)

struct 和 class 构造函数理解

typedef struct LNode{
    Elempty data;
    struct LNode* next;
}LNode,*LinkList;
//上面相当于:typedef 一个重新命名的作用。
//typedef struct LNode* LinkList;
//typedef struct LNode LNode; 

上面的定义的是单链表中每个结点的存储结构,它包括两部分:存储节点的数据域,存储后继节点位置的指针域 next;两个的类型,由以上定义可知。为了提高程序的可读性,对同一结构体指针类型起了两个名称,LinkList,LNode*,两者本质是等价的。通常习惯上用 LinkList 定义单链表,强调定义的是某个单链表的头指针。用LNode* 定义指向单链表中任意结点的指针变量。例如:若定义 LinkList L ,则L为单链表的头指针, 若定义LNode* p,则p为指向单链表中某个结点的指针。用 *p 代表该结点。

单链表是由表头指针唯一确定,因此单链表可以用头指针的名字命名。 注意区分 指针变量 和 结点变量 两个不同的概念,若定义 LinkList p 或者 LNode* p,则 p 为指向某结点的指针变量,表示该结点的地址,而*p 为对应的结点变量,表示该结点的名称。 

因此,不同的方式,访问的方式也不一样,指针访问:p -> data || p -> next    或者 (*p).data || (*p).next。

  • 做题常见

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) {}
};

在做题中,只用一个名字 ListNode 去操作,并且有构造函数,在操作的时候方便。

2、虚拟头结点

增加虚拟头节点的作用:1)便于首元结点(链表中存储第一个数据元素的结点)的处理:增加了虚拟头结点之后,首元结点的地址保存在虚拟头结点的指针域中,则对链表的第一个数据元素的操作与其他数据元素相同,无需进行特殊处理。(例如删除元素);2)便于空表和非空表的统一处理:

例题:给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

数据结构,单链表及一些题目_第1张图片

这个题的解法就是,申请了一个虚拟头结点,使其的 next 指向第一个数据元素,这样就不需要判断是否删除第一元素的情况了,方便统一。

/**
 * 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* removeElements(ListNode* head, int val) {
        ListNode dummy_head;
        dummy_head.next = head;
        ListNode* cur = &dummy_head;
        
        //上面的写法,在最后不需要删除 dummy_head,因为属于栈内的变量,随着作用域结束就销毁了。
        /*
        下面这种写法,最后要记得删除  因为虚拟头结点是 new出来的。
        ListNode* dummy_head = new ListNode(0);
        dummy_head->next = head;
        ListNode* cur = dummy_head;
        //这样写的话,后面就要删除dummy_head; delete dummy_head;
        */
        while (cur->next != nullptr) {
            if (cur->next->val == val) {
                ListNode* tem = cur->next;
                cur->next = tem->next;
                delete tem;//做题的时候,可以不写,但是工作中必须写,不然会造成内存泄漏
            }
            else {
                cur = cur->next;
            }
        }

        return dummy_head.next;
    }
};

3、设计链表的几个操作

初始化;得到第i个元素值;在头部添加,在尾部添加,在第i个结点前添加,删除第i个元素等等。

https://leetcode-cn.com/problems/design-linked-list/

4、链表常考察的几个题目

反转链表: https://leetcode-cn.com/problems/reverse-linked-list/

删除倒数第n个结点:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/

环形链表:https://leetcode-cn.com/problems/linked-list-cycle/

https://leetcode-cn.com/problems/linked-list-cycle-ii/

5、STL中 单链表和双向链表

#include  //单向链表
#include   //双向链表
using namespace std;

 

你可能感兴趣的:(C++,STL学习,单链表,数据结构)