文章目录

  • 目录
    • 链表的基本概念
      • 1.数组和链表
    • 链表的使用
      • 1.链表的简单使用
      • 2.链表的进阶使用
      • 3.链表的高阶使用
      • 4.链表的其他操作
    • 链表容器list
      • 1.list介绍
      • 2. list使用
      • 3. list与vector之间的区别
      • 4.list例子代码

目录

  • 数据结构:

    • 逻辑结构:数组,栈,队列,字符串,树,图
    • 存储结构:顺序存储,链式存储
  • C++常用的数据结构有:string , stack , queue , deque , vector , list , map , iterators.

链表的基本概念

链表是一种线性表,其在内存中以链式结构存储,所以叫做链表。具有插入和删除方便,但是访问则必须从链表的头开始。

1.数组和链表



链表的使用

1.链表的简单使用

一个个节点按顺序串接起来,就构成了链表。显然这一个个节点是很关键的,假设我们要构造一个int类型的链表,那么一个节点中就需要包含两个元素:

  • 一个是当前节点所保存的值,设为int value。
  • 另一个就是指向下一个节点的指针,我们再假设这个节点类是node,那么这个指针就是 node *next。

这里一定不是int *next。因为这个指针指向的下一个元素是一个类的实例,而不是int类型的数据。那么node这个类最简单的实现就如下:

class node
{
public:  int value;  node *next;  node()  {  value = 0;  next = NULL;  }
};

这个类名字为node,包含两个元素,一个是当前node的值,一个是指向下一个节点的指针,还有一个构造函数,分别将value初始化为0、next初始化为NULL
拿到这个类以后,假设我们生成两个这个类的实例,node1和node2,再将node1的next指针指向node2,就构成了有两个元素的链表。这样如果我们拿到node1这个节点,就可以通过next指针访问node2。比如下面的代码

#include <iostream>
#include <deque>using namespace std;class node{public:int value;//链表节点的数据域node* next;//用于指向下一个节点,是链表中的指针域node():value(0),next(NULL){};//默认构造函数node(int value):value(value),next(NULL){};//带参数的构造函数 ~ node(){cout<<"delete the node!!!"<<endl;delete next; // 删除节点的指针域 }
}; int main(){node mNode1(1),mNode2(2),mNode3(3),mNode4(4);mNode1.next = &mNode2;mNode2.next = &mNode3;mNode3.next = &mNode4;cout<<"the value of node3 is :"<<mNode3.value<<endl;  //直接输出节点 cout<<"the value of node3 is :"<<mNode1.next->next->value<<endl;  //通过链表查找 return 0;
}

the value of node3 is :3
the value of node3 is :3
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!

2.链表的进阶使用

上述这样就构成了一个最简单的链表,如果还有新的节点出现,那么就如法炮制,链在表尾或者表头,当然插在中间也是没问题的。

但是这样还有个问题就是node1和node2是我们提前声明好的,而且知道这两个实例的名称,如果我们需要1000甚至跟多节点,这种方式显然是不科学的,而且在很多时候,我们都是动态生成一个类的实例,返回的是这个实例的首地址。

下面的代码我们用一个for循环,生成11个节点,串起来形成一个链表
原理就是先生成一个头结点,然后动态生成10个节点,每生成一个节点,就将这个节点指向头结点,然后更新头结点为当前节点

#include <iostream>
#include <deque>using namespace std;class Node{public:int value;//链表节点的数据域Node* next;//用于指向下一个节点,是链表中的指针域Node():value(0),next(NULL){};//默认构造函数Node(int value):value(value),next(NULL){};//带参数的构造函数 ~ Node(){cout<<"delete the node!!!"<<endl;delete next; // 删除节点的指针域 }
}; int main(){Node *head , *curr;  //定义头结点指针和当前插入节点的指针head = new Node();//头插法生成链表 for(int i = 0 ; i < 10 ; i++ ){curr = new Node(i);if(curr==NULL){cerr<<"内存分配失败!"<<endl; }else{curr->next = head->next;  //将当前节点指针指向之前头结点指向的地方head->next = curr;  //头结点指向当前的节点cout<<"the value is : "<<curr->value<<endl;}}return 0;
}

the value is : 0
the value is : 1
the value is : 2
the value is : 3
the value is : 4
the value is : 5
the value is : 6
the value is : 7
the value is : 8
the value is : 9

那么链表该如何遍历呢,刚开头的时候就说,遍历链表需要从头到尾,访问每一个元素,直到链表尾。也就是说不断地访问当前节点的next,直到NULL。下面是链表的遍历输出

#include <iostream>using namespace std;class Node{public:int value;//链表节点的数据域Node* next;//用于指向下一个节点,是链表中的指针域Node():value(0),next(NULL){};//默认构造函数Node(int value):value(value),next(NULL){};//带参数的构造函数 ~ Node(){cout<<"delete the node!!!"<<endl;delete next; // 删除节点的指针域 }
}; int main(){Node *head , *curr;head = new Node();//头插法生成链表 for(int i = 0 ; i < 10 ; i++ ){curr = new Node(i);if(curr==NULL){cerr<<"内存分配失败!"<<endl; }else{curr->next = head->next;head->next = curr;
//          cout<<"the value is : "<<curr->value<<endl;}}//链表的遍历while(head){cout<<"current data is : "<<head->value<<endl;head = head->next;} return 0;
}

current data is : 0
current data is : 9
current data is : 8
current data is : 7
current data is : 6
current data is : 5
current data is : 4
current data is : 3
current data is : 2
current data is : 1
current data is : 0

3.链表的高阶使用

链表相对于数组有个非常明显的优点就是能以时间复杂度o(1)完成一个节点的插入或者删除操作。

插入操作的原理很简单,假设现在有三个节点,一个是当前节点curr,一个是当前节点的下一个节点,也就是后继节点,假设为next,还有一个待插入的节点,假设为insert。插入操作就是让当前节点的后继节点指向insert节点,insert节点的后继节点指向next节点。以下是示意图

删除操作的原理也是类似的,就是让当前节点的后继节点指向它后继节点的后继节点。示意图如下

那么插入和删除操作用代码如何实现呢,我们还用原先的链表,先插入一个值为20的节点,输出链表的全部元素。然后再删除链表中这个值为20的元素,输出元素的全部内容。代码如下:

#include <iostream>
#include <deque>using namespace std;class Node{public:int value;//链表节点的数据域Node* next;//用于指向下一个节点,是链表中的指针域Node():value(0),next(NULL){};//默认构造函数Node(int value):value(value),next(NULL){};//带参数的构造函数 ~ Node(){cout<<"delete the node!!!"<<endl;delete next; // 删除节点的指针域 }
}; int main(){Node *head , *curr;head = new Node();//头插法生成链表 for(int i = 0 ; i < 10 ; i++ ){curr = new Node(i);if(curr==NULL){cerr<<"内存分配失败!"<<endl; }else{curr->next = head->next;head->next = curr;}}//链表的插入curr = head;while(curr->value != 5){   //第一步:找到要插入的节点的前驱 curr = curr->next;}cout<<"curret node is : "<<curr->value<<endl;Node* insertNode = new Node(55);  //创建要插入的节点 insertNode->next = curr->next;  //第二步:将插入的节点的指针域指向当前节点的后继 curr->next = insertNode;  //第三步:将当前节点的指针指向插入的新节点//链表遍历curr = head;while(curr){cout<<"the value is : "<<curr->value<<endl;curr = curr->next;}//链表元素的删除//第一步找到要删除的节点的前继curr = head;while(curr->next->value != 55){curr = curr->next;}cout<<"curret node is : "<<curr->value<<endl;Node *tempNode;tempNode = curr->next;  //第二步:保存下要删除的节点 curr->next = tempNode->next; //第三步:将要删除节点的前继指针指向要删除节点的后继 delete tempNode;  //第四步:删除当前的节点//链表遍历curr = head;while(curr){cout<<"the value is : "<<curr->value<<endl;curr = curr->next;}return 0;
}

curret node is : 5
the value is : 0
the value is : 9
the value is : 8
the value is : 7
the value is : 6
the value is : 5
the value is : 55
the value is : 4
the value is : 3
the value is : 2
the value is : 1
the value is : 0
curret node is : 5
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
the value is : 0
the value is : 9
the value is : 8
the value is : 7
the value is : 6
the value is : 5
the value is : 4
the value is : 3
the value is : 2
the value is : 1
the value is : 0
至于完整的链表,STL中有标准的库,也有功能非常全面的API,只要我们知道内部的实现原理,调用这些API是非常简单的事,用起来也会得心应手。

4.链表的其他操作

// 在末尾加入新的结点
void AddToTail(ListNode** pHead, int value){ListNode* pNew = new ListNode();pNew->val = value;pNew->next = nullptr;if (*pHead == nullptr){*pHead = pNew;}else{ListNode* pNode = *pHead;while(pNode->next != nullptr)pNode = pNode->next;pNode->next = pNew;}return;
}// 删除某个值为value的结点
void RemoveNode(ListNode** pHead, int value){if(pHead == nullptr || *pHead == nullptr) return;ListNode* pToDeleted = nullptr;if((*pHead)->val == value){pToDeleted = *pHead;*pHead = (*pHead)->next;}else{ListNode* pNode = *pHead;while(pNode->next != nullptr && pNode->next->val != value)pNode = pNode->next;if(pNode->next != nullptr && pNode->next->val == value){pToDeleted = pNode->next;pNode->next = pNode->next->next;}}if(pToDeleted != nullptr){delete pToDeleted;pToDeleted = nullptr;}return;
}

链表容器list

1.list介绍

2. list使用


3. list与vector之间的区别

4.list例子代码

#include <iostream>
#include <list>using namespace std;int main(){list<int> c1;list<int>::iterator c1_iter;//向链表的末尾加入元素 c1.push_back(1);c1.push_back(2);c1.push_back(3);//使用迭代器访问链表 for(c1_iter = c1.begin();c1_iter != c1.end();c1_iter++){cout<<"data is : "<<*c1_iter<<endl;}//将链表反转 c1.reverse();for(c1_iter = c1.begin();c1_iter != c1.end();c1_iter++){cout<<"reverse data is : "<<*c1_iter<<endl;}return 0;
}

data is : 1
data is : 2
data is : 3
reverse data is : 3
reverse data is : 2
reverse data is : 1

#include <list>
#include <iostream>  int main( )
{  using namespace std;  list <int> c1;  list <int>::iterator c1_Iter;  c1.push_back( 20 );  c1.push_back( 10 );  c1.push_back( 30 );  cout << "Before sorting: c1 =";  for ( c1_Iter = c1.begin( ); c1_Iter != c1.end( ); c1_Iter++ )  cout << " " << *c1_Iter;  cout << endl;  c1.sort( );  cout << "After sorting c1 =";  for ( c1_Iter = c1.begin( ); c1_Iter != c1.end( ); c1_Iter++ )  cout << " " << *c1_Iter;  cout << endl;  c1.sort( greater<int>( ) );  cout << "After sorting with 'greater than' operation, c1 =";  for ( c1_Iter = c1.begin( ); c1_Iter != c1.end( ); c1_Iter++ )  cout << " " << *c1_Iter;  cout << endl;
}

Before sorting: c1 = 20 10 30
After sorting c1 = 10 20 30
After sorting with ‘greater than’ operation, c1 = 30 20 10

数据结构和算法(05)---链表(c++)相关推荐

  1. 【数据结构和算法05】 红-黑树(转发)

    2019独角兽企业重金招聘Python工程师标准>>> [数据结构和算法05] 红-黑树(看完包懂~) 置顶 2016年04月13日 15:50:25 eson_15 阅读数:526 ...

  2. python定义链表节点_Python数据结构与算法之链表定义与用法实例详解【单链表、循环链表】...

    本文实例讲述了Python数据结构与算法之链表定义与用法.分享给大家供大家参考,具体如下: 本文将为大家讲解: (1)从链表节点的定义开始,以类的方式,面向对象的思想进行链表的设计 (2)链表类插入和 ...

  3. 数据结构与算法之链表结构寻找p、q最近的公共祖先

    链表结构,寻找p.q最近的公共祖先 数据结构与算法之链表结构寻找p.q最近的公共祖先 链表结构,寻找p.q最近的公共祖先 问题 想法 代码 问题 设一棵二叉树的结点结构为(LLINK, INFO, R ...

  4. 数据结构与算法--单链表相关面试题

    此文章仅作为自己学习过程中的记录和总结,同时会有意地去用英文来做笔记,一些术语的英译不太准确,内容如有错漏也请多指教,谢谢! 一.概述 获取单链表的有效元素个数[新浪面试题1] 获取单链表倒数第k个结 ...

  5. 数据结构与算法 内核链表实现商品购物系统项目+Makefile

    数据结构与算法 内核链表实现商品购物系统项目 第一章 项目实现思维 [1]编译介绍 [2]框架思维 第二章 Makefile编写 第三章 代码编写实现 [1]favorite.txt文件 [2]his ...

  6. 一文通数据结构与算法之——链表+常见题型与解题策略+Leetcode经典题

    文章目录 1 链表 1.1 常见题型及解题策略 1.1.1 LeetCode中关于链表的题目有以下五种类型题: 1.1.2 解题策略 1.2 链表的基本内容 1.2.1 链表的基本结构: 1.2.2 ...

  7. JS数据结构与算法_链表

    上一篇:JS数据结构与算法_栈&队列 下一篇:JS数据结构与算法_集合&字典 写在前面 说明:JS数据结构与算法 系列文章的代码和示例均可在此找到 上一篇博客发布以后,仅几天的时间竟然 ...

  8. java数据接口之链表_Java数据结构和算法之链表

    三.链表 链结点 在链表中,每个数据项都被包含在'点"中,一个点是某个类的对象,这个类可认叫做LINK.因为一个链表中有许多类似的链结点,所以有必要用一个不同于链表的类来表达链结点.每个LI ...

  9. 数据结构与算法--复杂链表的复制

    复杂链表的复制 题目:实现一个函数complexListNode 复制一个复杂链表.在链表中,每个节点除了有一个next指针指向下一个节点,还有另外一个before节点,before节点指向链表中任意 ...

  10. 数据结构与算法之-----链表(List)

    [ 写在前面的话:本专栏的主要内容:数据结构与算法. 1.对于​​​​​​​初识数据结构的小伙伴们,鉴于后面的数据结构的构建会使用到专栏前面的内容,包括具体数据结构的应用,所使用到的数据结构,也是自己 ...

最新文章

  1. 百度离职员工吐槽:整天除了工作还要演好戏,拍马屁,心太累!
  2. simulink显示多个数据_Stateflow数据介绍(一)
  3. java is a_java中 is - a和 has - a的区别
  4. 项目中遇到难题一 : 多条件筛选(同一本小说具有多个特征)
  5. 针对深度学习的GPU芯片选择
  6. mybatisplus 强制制空 空覆盖原来的字符串
  7. python基于水色图像的水质评价_零基础学习Python的学习路线及教程
  8. Spark.shuffle.io.maxRetries参数
  9. 探究Ptcms小说采集规则
  10. 郝斌数据结构-线性表之单链表程序(C语言版)
  11. R语言---相关系数
  12. Win10,Win11家庭版开启远程桌面接入功能-有详细操作截屏
  13. 【2019.06.21】基于Airtest的微信朋友圈自动点赞脚本设计与实现 2019.06.21脚本正常运行
  14. python实现多EXCEL表格合并xls、xlsx格式
  15. 通过PS把普通数码照片制作成素描照片
  16. mysql order by empty_MySQL随笔一
  17. 如何快速将手写数据录入 Excel
  18. 炫酷超拽!推荐一款Vue开发的OA系统,功能还不错哟!!!
  19. Fortran语法汇总(上)
  20. Android-Notes|BottomNavigationView-爱上-Lottie,android高级开发面试题

热门文章

  1. 微星主板rgb_虽然这块主板价格有点小贵,但用过之后,感觉还是可以接受的
  2. inputstream java_Java实现inputstream流的复制
  3. 列表反向组成数字相加,并输出数组反向组成列表
  4. 公共链接url出错_SEO优化技巧:关于URL的优化方法
  5. 应用程序标准输入输出、Shell、程序界面的关系
  6. Angular使用Console.log()打印出来的数据没问题,点击详情后数据变了
  7. 【HDU - 5475】An easy problem(线段树,思维)
  8. 【CodeForces - 289E 】Polo the Penguin and XOR operation (数学,异或,贪心)
  9. Apollo进阶课程㊷丨Apollo实战——车辆与循迹驾驶能力实战
  10. 8.深度学习练习:Gradient Checking