数据结构与算法学习task02

0.理论部分

0.1 线性表的定义

线性表(Linear List)是由n(n >= 0)个相同类型的数据元素a1,a2,…,an 组成的有序序列。即表中除首尾元素外,其它元素有且仅有一个直接前驱和直接后继。首元素仅有一个直接后继,尾元素仅有一个直接前驱。表中数据元素的个数称为表的长度,记为:(a1,a2,…,an)。

0.2 线性表的操作

  1. 随机存取:获取或设置指定索引处的数据元素值。(支持索引器)
  2. 插入操作:将数据元素值插入到指定索引处。
  3. 移除操作:移除线性表指定索引处的数据元素。
  4. 查找操作:寻找具有特征值域的结点并返回其下标。
  5. 得到表长:获取线性表中实际包含数据元素的个数。
  6. 是否为空:判断线性表中是否包含数据元素。
  7. 清空操作:移除线性表中的所有数据元素。

0.3 顺序存储(顺序表)
在这里插入图片描述
0.4 链式存储(链表)

利用指针方式实现的线性表称为链表(单链表、循环链表、双链表)。它不要求逻辑上相邻的数据元素在物理位置上也相邻,即:逻辑结构与物理结构可以相同也可以不相同。
单链表:
在这里插入图片描述
循环链表:
在这里插入图片描述
双向链表:
在这里插入图片描述
学习目标:

  • 理解线性表的定义与操作。
  • 实现顺序表。
  • 实现单链表、循环链表、双向链表。

1. 合并两个有序链表

https://leetcode-cn.com/problems/merge-two-sorted-lists/

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例:
输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
思路
首先判断两个链表是否有空集的情况,一个为空返回另一个,两个都为空返回null。然后因为都是有序链表生成一个新的有序链表,比较大小然后穿插成一个即可。最后直到有一个链表为空,再将另一个链表链到新链表后即可。

C++代码如下:

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(!l1 && !l2)
            return NULL;
        if(!l1 && l2)
            return l2;
        if(l1 && !l2)
            return l1;

        ListNode* head = new ListNode(-1);
        ListNode* p = head, *q;

        while(l1 && l2){
            if(l1->val < l2->val){
                q = new ListNode(l1->val);
                p->next = q;
                p = q;
                l1 = l1->next;
            }
            else{
                q = new ListNode(l2->val);
                p->next = q;
                p = q;
                l2 = l2->next;
            }
        }

        if(l1)
            l2 = l1;
        p->next = l2;

        return head->next;

    }
};

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

https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

说明:给定的 n 保证是有效的。

进阶:你能尝试使用一趟扫描实现吗?

思路:
使用双指针法。front节点和rear节点之间有n 个节点,并同时向后移动。当rear为NULL时停止窗口移动,并删除front->next节点。时间复杂度为O(n)。

参考:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/solution/c-shuang-zhi-zhen-kuai-su-jie-ti-zhu-shi-by-y36ymh/

C++代码如下:

class Solution{
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* front = head;
        ListNode* rear = head;
        if(head->next == NULL) return NULL;
        while(n-- >= 0){
            if(rear == NULL) return head -> next;
            rear = rear->next;
            // n --;
        }
        while(rear){
            rear = rear -> next;
            front = front -> next;
        }
        front->next = front->next->next;
        return head;
    }
};

3. 旋转链表

https://leetcode-cn.com/problems/rotate-list/

给定一个链表,旋转链表,将链表每个节点向右移动k个位置,其中k是非负数。

示例 1:

输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL

解释:
向右旋转 1: 5->1->2->3->4->NULL
向右旋转 2: 4->5->1->2->3->NULL

示例 2:

输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL

解释:
向右旋转 1: 2->0->1->NULL
向右旋转 2: 1->2->0->NULL
向右旋转 3: 0->1->2->NULL
向右旋转 4: 2->0->1->NULL

思路:
移动元素k位,相对于移动head(N - k % N)位,且新链表的尾结点在该新head的前一位(N - k % N - 1)。

首先,记录结点个数,并且做成环链表;
然后,计算N - k % N,这个head移动该步数后,新head所在的位置;
最后,移动head(N - k % N - 1)位,得到新链表的尾指针,该指针的下一位即新表的头结点。

参考:https://leetcode-cn.com/problems/rotate-list/solution/yuan-de-xiang-dui-yi-dong-zhe-yang-jie-shi-by-leaf/

class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if(head == NULL) return head;//指针为空,直接返回
        
        int N = 1;
        ListNode* tail = head;
        while(tail -> next) {
            tail = tail -> next;
            N++;
        }
        tail -> next = head; // 首尾相连,做环
        
        k = N - k % N; // head的相对移动数(注意这个地方的理解)
        // 对head少移动1位,得到新表尾指针的位置
        while(k - 1) {
            head = head -> next;
            k--;
        }
        tail = head; 
        head = head -> next;
        tail -> next = NULL;
        
        return head;//返回新链表
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值