c++基础知识——STL之链表

简介: c++基础知识——STL之链表

一、什么是链表


链表是动态存储分配的数据结构。链表的每个结点都是一个结构体变量,包含数据域(存放数据本身)和指针域(存放下一个结点)的地址;

结构体可以定义为以下方式:

struct Node{

int data;

Node*next;

};


二、链表的分类


顺序链表


由多个结点组成的一条线性的数据结构;


链表结构图


ea6fce4c13eb387a9e6ca0a52656b518_2dfde0b378d94b79bbbdc1d4091a5078.png


代码如下(示例):


#include<iostream>
using namespace std;
struct Node
{
  int data;
  Node* next;
};
//创建顺序链表
Node* creatNode(int n)
{
  Node* headnode = new Node;//申请动态空间;
  headnode->next = NULL;
  Node* p = headnode;
  while (n--)
  {
  Node* q = new Node;
  cin >> q->data;
  q->next = p->next;
  p->next = q;
  p = q;//每次把头结点后移,重复上面操作;
  }
  return headnode;
}
//链表的打印;
void printList(Node* headnode)
{
  Node* pmove=headnode->next;
  while (pmove)
  {
  printf("%5d", pmove->data);
  pmove = pmove->next;
  }
}
//调试函数;
int main(void)
{
  int n;
  Node *list;
  cin >> n;
  list = creatNode(n);
  printList(list);
}


3556c8a231ed216dae6d441e0753048a_d3c258d0072d45638042fc677b0e04e0.png


2.逆序链表


其实说白了逆序链表就是先进入的结点向后走,后进的结点在前,然后遍历,就可以得到逆序链表;


c60c7dd465776f47dc5062b03aec3ea0_5b44405543364af6aa2b1d091dcefc64.png


代码如下(示例):


#include<iostream>
#include<assert.h>
using namespace std;
struct Student
{
  int data;
  Student* next;
};
//构建链表;
Student* Init_headnode()
{
  Student* headnode = new Student;
  headnode->next = NULL;
  return headnode;
}
//链表的构建;
void creatList(Student* headnode, int n)
{
  assert(headnode != NULL);
  Student* p = headnode;
  while (n--)
  {
  Student* newnode = new Student;
  cin >> newnode->data;
  newnode->next = p->next;
  p->next = newnode;
  }
}
//打印链表函数
void printList(Student* headnode)
{
  assert(headnode != NULL);
  Student* pmove = headnode->next;
  while (pmove)
  {
  printf("%5d", pmove->data);
  pmove = pmove->next;
  }
}
//调试函数;
int main(void)
{
  Student* headnode= Init_headnode();
  int n;
  cin >> n;
  creatList(headnode, n);
  printList(headnode);
}


f2fe0560dc6c05c4fdc0d1b660bd9c30_5f4e71f959db4363bf7741e4f973269f.png


通过这两个例子,我们可以认识到链表,链表的操作还有很多,比如删除特定的值,或者特定位置插入,删除表头,清空链表,判空以及排序等一系列的操作方式,但是如果每个操作都定义一个函数,这样太过麻烦,那我们有没有什么模板来简化这些问题喃?这就是我们今天讲的STL(模板)之链表(list)


eaafd8a8da823f63d9399702006d75e0_f924e9d5f53449b9bee0d998864490d2.png


链表的库函数(模板函数)


8392f41ea58f8b32dde799a74c0c32d3_ad0edab43bed4cb88e560510de0c61d3.png


b7b3af7773062ac17397bede814b4031_5073809d18fc4c84b3125b3956ae4ed8.png


代码演示:


#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<list>//包含头文件,引用STL中的list模板
using namespace std;
list<int>createList(int n)//建立顺序链表
{
  list<int>myList;
  int t;
  for (int i = 0; i < n; i++)
  {
  cin >> t;
  myList.push_back(t);//将t连接到链表的尾部;
  }
  return myList;
}
//输出链表;
void prtList(list<int>myList)
{
  list<int>::iterator it;//list<int>::iterator类型迭代器;
  for (it = myList.begin(); it != myList.end(); it++)//注意,在STL模板中,迭代器没有小于号的重载,故只能用it!=myList.end()来结束;
  {
  if (it != myList.begin())
    cout << "  ";
  cout << *it;  //此时it就相当于c语言中的一个结构体指针;
  }
  cout << endl;
}
//比较函数;降序排列;
bool cmp(int a, int b)
{
  return a >= b;
}
//调试函数;
int main(void)
{
  int n;
  cin >> n;
  list<int>myList = createList(n);
  prtList(myList);
  cout << myList.size() << endl;//获取链表的长度;
  myList.push_front(3);//在链表的头部位置加入3;
  myList.push_back(3);//在链表的尾部位置加入3;
  prtList(myList);
  myList.reverse();//链表的逆置;
  prtList(myList);//归并链表;
  myList.merge(myList,cmp);
  myList.sort(cmp);//按照降序排列;
  prtList(myList);
}



链表中的这些函数不用去背,一般在编译器上会有提示,不过要熟练掌握他的格式和用意。这些模板为我们解决一些问题减少了很多时间,方便,所以熟练掌握这些很重要;


STL之list的应用


#include<iostream>
#include<list>
using namespace std;
struct Node
{
  string name;
  int age;
};
//创建链表;
list<Node>creatListQueue(int n)
{
  list<Node>myList;
  Node t;
  for (int i = 0; i < n; i++)
  {
  cin >> t.name >> t.age;
  myList.push_back(t);
  }
  return myList;
}
//打印函数;
void prtList(list<Node>myList)
{
  list<Node>::iterator it;
  for (it = myList.begin(); it != myList.end(); it++)
  {
  if (it != myList.begin())
    cout << "  ";
  cout << it->name << it->age;
  }
  cout << endl;
}
//排序函数;
bool cmp(Node a, Node b)
{
  if (a.age != b.age)
  return a.age > b.age;
  return a.name < b.name;
}
//调试函数;
int main(void)
{
  int n;
  cin >> n;
  list<Node>myList=creatListQueue(n);
  prtList(myList);
    //对链表进行排序;
  myList.sort(cmp);
  prtList(myList);
  myList.reverse();//逆置链表;
  prtList(myList);
  Node t;
  cin >> t.name >> t.age;
  myList.insert(myList.begin(), t);
  prtList(myList);
}


总结


前面我们学习了STL之vector,仔细观察,这些模板之间都有很多相似之处,所以不需要去背这些代码,学会活学活用才最好,本节的list模板就讲到这里,其中有很多的模板函数在我们去实现代码的时候会有很大的帮助,尤其是一些常用的函数,上面我列举的函数都比较常用,需要熟练掌握;

相关文章
|
12天前
|
算法 C语言 C++
【c++丨STL】list的使用
本文介绍了STL容器`list`的使用方法及其主要功能。`list`是一种双向链表结构,适用于频繁的插入和删除操作。文章详细讲解了`list`的构造函数、析构函数、赋值重载、迭代器、容量接口、元素访问接口、增删查改操作以及一些特有的操作接口如`splice`、`remove_if`、`unique`、`merge`、`sort`和`reverse`。通过示例代码,读者可以更好地理解如何使用这些接口。最后,作者总结了`list`的特点和适用场景,并预告了后续关于`list`模拟实现的文章。
28 7
|
29天前
|
存储 编译器 C语言
【c++丨STL】vector的使用
本文介绍了C++ STL中的`vector`容器,包括其基本概念、主要接口及其使用方法。`vector`是一种动态数组,能够根据需要自动调整大小,提供了丰富的操作接口,如增删查改等。文章详细解释了`vector`的构造函数、赋值运算符、容量接口、迭代器接口、元素访问接口以及一些常用的增删操作函数。最后,还展示了如何使用`vector`创建字符串数组,体现了`vector`在实际编程中的灵活性和实用性。
55 4
|
1月前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
72 5
|
1月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
51 2
|
1月前
|
存储 算法 Linux
【c++】STL简介
本文介绍了C++标准模板库(STL)的基本概念、组成部分及学习方法,强调了STL在提高编程效率和代码复用性方面的重要性。文章详细解析了STL的六大组件:容器、算法、迭代器、仿函数、配接器和空间配置器,并提出了学习STL的三个层次,旨在帮助读者深入理解和掌握STL。
55 0
|
15天前
|
存储 编译器 C语言
【c++丨STL】vector模拟实现
本文深入探讨了 `vector` 的底层实现原理,并尝试模拟实现其结构及常用接口。首先介绍了 `vector` 的底层是动态顺序表,使用三个迭代器(指针)来维护数组,分别为 `start`、`finish` 和 `end_of_storage`。接着详细讲解了如何实现 `vector` 的各种构造函数、析构函数、容量接口、迭代器接口、插入和删除操作等。最后提供了完整的模拟实现代码,帮助读者更好地理解和掌握 `vector` 的实现细节。
27 0
|
2月前
|
存储 程序员 C++
C++常用基础知识—STL库(2)
C++常用基础知识—STL库(2)
85 5
|
1月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
106 5
|
1月前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
97 4
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
116 4