链表及基本操作

  • 定义
  • 基本操作
    • 1. 创建单链表
    • 2. 插入节点
    • 3. 删除节点
    • 4. 反转链表
    • 5. 倒数第K个节点
    • 6. 是否有环

本文所述均为单向链表。
ps:更多数据结构知识详见:
常见数组结构与算法

定义

链表:由一系列结点(链表中每一个元素称为结点)组成,每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

typedef struct ListNode{int val;struct ListNode* next;ListNode(int x) :val(x), next(NULL){}
};

基本操作

1. 创建单链表

后面的操作均在其基础上进行修改
步骤:

  1. 创建头节点head,并且将当前结点p指向头结点(p=head)
  2. 创建下一个结点q,当前结点p的下一结点为q(p->next=q)
  3. 结点p后移一位(p = p->next)
#include <iostream>
#include<vector>using namespace std;struct ListNode{int val;struct ListNode* next;ListNode(int x) :val(x), next(NULL){}
};int main(){int num;cin >> num;ListNode* head = new ListNode(num);ListNode* p = head;//利用尾插法创建一个链表while (cin >> num){ListNode* q = new ListNode(num);p->next = q; p = p->next;}//遍历这个链表,并输出每个结点的元素ListNode* m = head;while (m != nullptr){cout << m->val << endl;m = m->next;}return 0;}

2. 插入节点

  1. 判断原链表是否是空链表,如果是,将head指向新增结点
  2. 如果不是空链表,向链表尾部插入新结点
ListNode* insertNode(ListNode* head, int data){ListNode* newNode = new ListNode(data);ListNode* p = head;if (p == nullptr){head = newNode;}else{while (p->next != nullptr){p = p->next;}p->next = newNode;}return head;
}

3. 删除节点

ListNode* deleteNode(ListNode* head, int data){ListNode* p = head;//首先判断是不是空链表if (p == nullptr){return head;}else{//判断是不是删除头节点if (p->val == data){head = p->next;delete p;return head;}else{//如果有该结点,遍历到待删除节点的前一节点while (p->next != nullptr && p->next->val != data){p = p->next;}//遍历完整个链表都没有待删除节点if (p->next == nullptr){return head;}else{ListNode* deleteNode = p->next;p->next = deleteNode->next;delete deleteNode;return head;}}}
}

4. 反转链表


如上图,假设在I开始反转,那么需要知道i前面的h,还要保留i后面的j,防止链表断裂
假设pNode是当前的节点,pPrev是pNode前面的节点,PNext是PNode后面的节点,那么:
        当pNode不为nullptr,且pNext不为nullptr的时候

  1. 将pNode指向pPrev(pNode->next = pPrev)
  2. 将pNode给pPrev(pPrev= pNode)
  3. 将pNext给pNode(pNode = pNext)
      当pNode不为nullptr,且pNext==nullptr的时候,把反转后的头部指向pNode
    注意:判断边界条件
#include <iostream>
#include<vector>using namespace std;struct ListNode{int val;struct ListNode* next;ListNode(int x) :val(x), next(NULL){}
};//反转链表
ListNode* reverse(ListNode* head){ListNode* pPrev = nullptr;ListNode* p = head;ListNode* pReverseHead = nullptr;while (p != nullptr){ListNode* pNext = p->next;if (pNext == nullptr){pReverseHead = p;}p->next = pPrev;pPrev = p;p = pNext;}return pReverseHead;
}int main(){int num;cin >> num;ListNode* head = new ListNode(num);ListNode* p = head;while (cin >> num){ListNode* q = new ListNode(num);p->next = q;p = p->next;}p->next = nullptr;ListNode* result = reverse(head);ListNode* node = result;while (node != nullptr){cout << node->val << endl;node = node->next;}return 0;}

5. 倒数第K个节点

思想:设置快慢指针,快指针比慢指针多走k-1步,那么快指针走到终点的时候,慢指针指向倒数第K个结点
注意K与链表节点个数的关系

ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {if (pListHead == nullptr || k == 0){return nullptr;}ListNode* pAhead = pListHead;//判断K是不是超出了链表的长度for (int i = 0; i< k - 1; i++){if (pAhead->next != nullptr){pAhead = pAhead->next;}else{return nullptr;}}ListNode* pBehind = pListHead;while (pAhead->next != nullptr){pAhead = pAhead->next;pBehind = pBehind->next;}return pBehind;}

6. 是否有环

判断链表是否有环,如果有,找出环的入口节点

  1. 判断链表是否有环
    思想:可以设置快慢指针,快指针一次走两步,慢指针一次走一步,如果快指针追上了走的慢的指针,那么链表有环,如果走到了链表尾部都没有追上,说明链表无环。
    注意:快指针与慢指针是否为nullptr的判断
  2. 如果有环,返回入口节点
    思想:返回的节点一定在环内,如果计算出环中节点的个数count,快指针比慢指针多走count步,那么两个指针相遇时,就是环的入口节点(参考上图)
//判断快慢指针是否相遇
ListNode* MeetNode(ListNode* pHead){ListNode* pNode = pHead;//判断链表是否为空if(pNode == nullptr){return nullptr;}//设置慢指针(慢指针不能为nullptr)ListNode* slowNode = pNode -> next;if(slowNode == nullptr){return nullptr;}//设置快指针ListNode* fastNode = slowNode -> next;while(fastNode != nullptr && slowNode != nullptr){//相遇返回快/慢指针if(fastNode == slowNode){return fastNode;}//slow走一步slowNode = slowNode ->next;//fast走两步(走下一步需要判读是不是为nullptr)fastNode = fastNode -> next;if (fastNode -> next != nullptr){fastNode = fastNode -> next;}}return nullptr;
}//计算环中节点的个数
int Count(ListNode* pMeet){int count = 0;ListNode* pNode = pMeet;while(pNode->next != pMeet){++count;pNode = pNode -> next;}++ count;return count;
}//计算环的入口节点
ListNode* EntryNodeOfLoop(ListNode* pHead)
{ListNode* meetNode = MeetNode(pHead);if (meetNode == nullptr){return nullptr;}int count = Count(meetNode);ListNode* aheadNode = pHead;ListNode* behindNode = pHead;for(int i = 0; i< count; i++){aheadNode = aheadNode ->next;}while(aheadNode != behindNode){aheadNode = aheadNode -> next;behindNode = behindNode -> next;}ListNode* result = aheadNode;return result;
}

【C++】链表及基本操作相关推荐

  1. 数据结构之【线性表】(顺序表、链表的基本操作实现)

    概念 线性表:是N个数据元素的有限序列. 顺序表:用一组地址连续的存储单元依次存储[线性表 ]的数据元素.(区别于有序表:表中的数据元素存在非递增或非递减有序) 链表:用一组任意的存储单元来存储[线性 ...

  2. 链表的基本操作 java_详细实现单链表的基本操作【Java版】

    节点类 static Node head=new Node(); static class Node{ int data; Node next; public Node() {//无参构造方法,默认d ...

  3. 链表c++语言 解析,C++ 单链表的基本操作(详解)

    链表一直是面试的高频题,今天先总结一下单链表的使用,下节再总结双向链表的.本文主要有单链表的创建.插入.删除节点等. 1.概念 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数 ...

  4. 《剑指offer》第二章小结(1)——链表的基本操作

    <剑指offer>第二章小结(1)--链表的基本操作 面试题5是从尾到头打印链表,与此相关的链表的基本操作应该知道. 下面代码中列举了单链表的创建.遍历.插入和删除四种操作.参考网址: h ...

  5. 【BUCTOJ】链表的基本操作

    原始题目 题题目描述 链表是数据结构中一种最基本的数据结构,它是用链式存储结构实现的线性表.它较顺序表而言在插入和删除时不必移动其后的元素.现在给你一些整数,然后会频繁地插入和删除其中的某些元素,会在 ...

  6. 链表的基本操作(C语言)详解(摘取自C语言学习网2.5)

    链表的基本操作(C语言)详解 #include <stdio.h> #include <stdlib.h>typedef struct Link{int elem;struct ...

  7. 单链表的基本操作-插入结点、删除结点、新建链表、查找结点位置

    ** C语言新手小白的学习笔记-------------目前持续更新中 ** 本人90后电气工程及其自动化大学生,大二开始接触C语言,写过前端,Python,但是都不精通,通过许多认识后明白了自身的许 ...

  8. 入门:链表的基本操作

    入门:链表的基本操作 标签:C语言 链表 By 小威威 1.写这篇博文的原因 C语言有三大重要部分:流程控制.函数.指针. 对于指针,单单了解它的简单应用是不够的,最重要的还是学习链表.许多参考书对链 ...

  9. 【Java】链表的基本操作

    链表主要是为了弥补一些顺序表的缺点: 顺序表的插入删除操作时间复杂度为 O(N) 增容需要申请新空间,拷贝数据,释放旧空间,会有不小的消耗 增容一般都是成2倍增长,会浪费一定的空间 为了解决以上问题引 ...

最新文章

  1. Spring中复杂类型注入
  2. 4.11-固件映像包 (FIP)
  3. 科技公司预备持jiu战:谷歌将允许员工在2021年7月前居家办公
  4. php空间限制磁盘限额,ORA-01536:超出表空间XXXX的空间限额
  5. jsp页面c标签循环map , c:foreach 循环map
  6. oracle状态blocked,oracle 监听状态为BLOCKED
  7. MSSQL 如何采用sql语句 获取建表字段说明、字段备注、字段类型、字段长度
  8. 插入排序---直接插入排序算法(Javascript版)
  9. 编写程序对给定的有向图(不一定连通)进行深度优先遍历_从零开始学习数据结构gt;图的非连通遍历...
  10. linux tar压缩文件命令,tar打包压缩文件命令
  11. 大一acmer日常记录day15
  12. 普渡大学 计算机金融,普渡大学金融数学专业排名2019年
  13. 自然常数e的由来(简单通俗易于理解自然常数e)
  14. linux mysql backdoor_Mysql BackDoor
  15. XFS (dm-0) I/O error问题修复
  16. python如何模拟微信扫码登录_python 微信扫码登录故障解决
  17. 录的视频太长怎么剪切?试试这个剪辑技巧
  18. 机器视觉——入门基础(一)—— 相机篇
  19. IE8 设置图片大小,没有效果
  20. Java---数据库---数据库DDL

热门文章

  1. 接口测试神器,它来了,它带着光环走来了
  2. 面经:2020校招中兴提前批面试经历
  3. 8g内存一般占用多少_电脑8G内存够用吗?
  4. 总结:word2007中插入页眉页脚和页码
  5. 油猴(tampermonkey)脚本安装及使用教程
  6. KNN算法和sklearn中的KNN算法
  7. vmvare workstation 15Pro密钥
  8. 使用 ab 对网站进行压力测试
  9. 如何在IDEA中写Java程序
  10. 什么是I3C总线?它和I2C和SMBus是什么关系?