既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
e = "King";
break;
}
return e;
}
// 描述牌信息 的 结构体======
struct Cards
{
CardSuits suit;
CardElements element;
};
// generate random suit and element card
int iSuit = GenerateRandomNumber(0, 3); // 四种花色中的一种,下标
int iElement = GenerateRandomNumber(0, 12);// 13种面值大小中的一种,下标
// 根据下标索引 int 创建 枚举变量=========================
// https://www.cnblogs.com/chio/archive/2007/07/18/822389.html
// static_cast < type-id > ( expression )
// 把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。
// 来源:为什么需要static_cast强制转换?
// 情况1:void指针 -> 其他类型指针,把void指针转换成目标类型的指针(不安全!!)
// 情况2:改变通常的标准转换,用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。
// 情况3:避免出现可能多种转换的歧义
CardSuits suit = static_cast(
iSuit);
CardElements element = static_cast(
iElement);
// 结构体=====================
//Cards card;
//card.suit = static_cast( GenerateRandomNumber(0, 3));
// card.element = static_cast( GenerateRandomNumber(0, 12));
// 打印牌 的字符串信息===============
cout << "Your card is ";
cout << GetElementString(element);// card.element
cout << " of " << GetSuitString(suit) << endl;//card.suit
#### 1.2 抽象数据结构 abstract data type class类实现
一种包含 变量和方法的 容器 或者 集合。
成员属性:
1. public 公开的,数据和方法可以被所有使用者访问
2. protected 保护的,数据和方法,可以被 类自己、类的继承者(子代)、类的朋友(同辈) 访问
3. private 私有的,数据和方法,可以被 类自己、类的朋友(同辈) 访问
struct 默认为 public属性,推荐 使用struct定义 数据集合,不包括方法
class 默认为 private属性
>
> 一个简单的类实现 给 动物Animal 起名字
>
>
>
class Animal // 定义一个 Animal 类
{
private:
// 私有变量,可以被 类自己、类的朋友(同辈) 访问
// main 函数等其他外部函数不可访问,但是可以通过 公开的函数间接访问
string m_name;
public:
// 给动物起名字
void GiveName(string name)
{
m_name = name;
}
// 获取该宠物的名字
// 外 部可以 通过 公开的函数间接访问 类内的私有变量=====
string GetName()
{
return m_name;
}
};
// 定义一个 动物类 实例 小狗
Animal dog = Animal();
// 该小狗对象 起名字为 “dog”
dog.GiveName(“dog”);
// 打印该小狗的名字
cout << "Hi, I’m a " << dog.GetName() << endl;
>
> 类构造函数实现
>
>
>
class Animal
{
private:
string m_name;
public:
// 类构造函数实现
Animal(string name) : m_name(name)
{ // 使用传入变量 name 为 类内私有变量 m_name 赋值
// 创建类实例式可传入对象的名字,省去了 命名函数
}
// 还是需要 通过公开的 方法 在外部 访问 类内变量
string GetName()
{
return m_name;
}
};
// 创建类实例式可传入对象的名字,省去了 命名函数
Animal dog = Animal(“dog”);
// 还是需要 通过公开的 方法 在外部 访问 类内变量
cout << "Hi, I’m a " << dog.GetName() << endl;
>
> 创建类的继承者,父类虚函数占坑,子类实现具体函数,基因遗传,豌豆杂交
>
>
>
class Animal // 动物类
{
private:
string m_name;
public:
// 构造函数
Animal(string name) : m_name(name)
{
}
// 不同的动物有不同的叫声,该动物大类下 设置一个虚函数 相当于先占坑,先占茅坑
// The interface that has to be implemented in derived class
// 等到继承者在实现,注意该函数前面 有 virtual 符号
virtual string MakeSound() = 0;
string GetName()
{
return m_name;
}
};
class Dog : public Animal // 小狗类Dog 公开 继承于 父类 Animal 动物
{
public:
// Forward the constructor arguments 转发构造函数参数?
Dog(string name) : Animal(name) {}// 直接使用 父类的 构造函数
// 在子类中实现具体的叫声函数(父类中定义的虚函数,占的茅坑)
string MakeSound() override // 注意后面跟着的 override
// C++ 11添加了两个继承控制关键字:override和final===========================
// override确保在派生类中声明的重载函数跟基类的虚函数有相同的签名。
// final阻止类的进一步派生和虚函数的进一步重载。
{
return "woof-woof!";// 旺旺雪饼好吃======
}
};
// 直接创建 之类的对象
Dog dog = Dog(“Bulldog”);
cout << dog.GetName() << " is barking: ";// 该函数是父类中的实现
cout << dog.MakeSound() << endl; // 该函数是之类中的实现
>
> 类的拷贝操作符重载实现,避免浅拷贝(shallow copying)问题
>
>
>
class Dog : public Animal // 之类Dog 公开继承 父类 Animal
{
public:
// Forward the constructor arguments
Dog(string name) : Animal(name) {} // 直接使用父类的构造函数
// 拷贝赋值运算符重载 实现====
void operator = (const Dog &D ) {
m_name = D.m_name;// 赋值名字
}
// C++ 11添加了两个继承控制关键字:override和final===========================
// override确保在派生类中声明的重载函数跟基类的虚函数有相同的签名。
// final阻止类的进一步派生和虚函数的进一步重载。
string MakeSound() override
{
return "woof-woof!";
}
};
// 创建类实例对象========================
Dog dog = Dog(“Bulldog”);
cout << dog.GetName() << " is barking: ";
cout << dog.MakeSound() << endl;
// 直接拷贝类=============================
Dog dog2 = dog;
cout << dog2.GetName() << " is barking: ";
cout << dog2.MakeSound() << endl;
#### 1.3 模板templates使用
>
> 函数模板 Function templates 接收一个类对象 模板为参数,打印同一类型 类对象的信息
>
>
>
class Cat : public Animal // 公开继承 父类 Animal
{
public:
// 调用父类的构造函数
Cat(string name) : Animal(name) {}
// 拷贝运算符重载======
void operator = (const Cat &D)
{
m_name = D.m_name;
}
// here we implement the interface
string MakeSound() override
{
return "meow-meow!"; // 与 dog 叫声不一样====
}
};
// 函数模板,接收一个类对象============
template // 注意关键字 template<typename *>=====
void GetNameAndMakeSound(T& theAnimal)
{
cout << theAnimal.GetName() << " goes "; // 名字
cout << theAnimal.MakeSound() << endl; // 叫声
}
// 使用同一个模板函数,打印同一类型 类对象的信息======
Dog dog = Dog(“Bulldog”);
GetNameAndMakeSound(dog);
Cat cat = Cat(“Persian Cat”);
GetNameAndMakeSound(cat);
>
> 类模板 Class templates 可接收类对象类型等其他任何类型
>
>
>
// 类模板内置类型 可以传入 类类型=============
template // 类内 变量的类型 为 模板
class AnimalTemplate // 类 名字
{
private:
T m_animal; // 模板类型 变量=== 可以直接传入类类型===
public:
AnimalTemplate(T animal) : m_animal(animal) {}
// 打印 信息
void GetNameAndMakeSound()
{
cout << m_animal.GetName() << " goes ";
cout << m_animal.MakeSound() << endl;
}
};
// 类实例 Dog
Dog dog = Dog(“Bulldog”);
// 传入 Dog类对象实例 构造 模板类实例====
AnimalTemplate dogTemplate(dog);
dogTemplate.GetNameAndMakeSound();
//
Cat cat = Cat(“Persian Cat”);
AnimalTemplate catTemplate(cat);
catTemplate.GetNameAndMakeSound();
>
> 标准模板库 Standard Template Library
>
>
>
算法 algorithms:排序sorting、搜索searching
容器 containers:存储数据/对象
迭代器 iterators: 迭代器,遍历值序列,begin(),end(), 反向迭代器rbegin(),rend()
函数 functions: 函数指针,函数对象
#### 1.4 算法分析
>
> 渐近分析 Asymptotic analysis
>
>
>
// 单层循环===该函数复杂度为 4n+1-------------------------------------> O(n)
void Looping(int n)
{
int i = 0; // 执行一次 赋值
while(i < n) // 1次比较====
{
cout << i << endl; // 1次打印====
i = i + 1; // 2次 = 1次加法 + 1次赋值===
}
}
// 双层循环====== 1+ n*( 1 + 1 + (4n) + 2 ) = 4n^2 + 4n +1 --------> O(n^2)
void Pairing(int n)
{
int i = 0; // 1次赋值
while(i < n) // 循环内 1次比较
{
int j = 0; // 循环内 1次赋值
while(j < n) // 二层循环内 1次比较
{
cout << i << ", " << j << endl; // 1次打印
j = j + 1; // 1次赋值 + 1次加法
}
i = i + 1;// 循环内 1次加法+1次赋值
}
}
>
> 最坏/平均/最好情况分析 Worst, average, and best cases
>
>
>
>
> “小于等于”O(big-Oh) “大于等于”Ω(big-theta) “等于”Θ(big-theta) “小于”o(little-oh)
>
>
>
f(n) = 4n + 1
时间复杂度为 O(n)
最坏情况时间复杂度 Θ(n)
最好情况时间复杂度 Θ(1)
### 章2 列表List & 链表 Linked List===================
#### 2.1 数组 array
>
> 内存地址连续
>
>
>
// 直接初始化 数组
int arr[] = { 21, 47, 87, 35, 92 };
// Access each element
cout << "Array elements: ";
// 数组元素数量
int array_num = sizeof(arr)/sizeof(*arr); // 数组总元素字节数量sizeof(arr), *arr数组首元素字节数量
for(int i = 0; i < array_num; ++i)
cout << arr[i] << " ";
cout << endl;
// 使用下标 直接修改 数组元素
arr[2] = 30;
arr[3] = 64;
// 再次 打印 数组元素
cout << "Array elements: ";
for(int i = 0; i < array_num; ++i)
cout << arr[i] << " ";
>
> new 分配数组,返回指针,使用指针访问元素
>
>
>
// Initialize tee array length
int arrLength = 5;
// 使用 new 分配数组内存空间 并返回首地址指针
int \* ptr = new int[arrLength] { 21, 47, 87, 35, 92 };
// 二维数组初始化
// int multiArray[][] = new int[3][5];
// 使用 \*解引用 来获取制造地址处的 值
cout << "Using pointer increment" << endl;
cout << "Value\tAddress" << endl;
while(\*ptr) // 不安全,数组后内地址一版存储的值为 0======
{
cout << \*ptr << "\t"; // 解引用,获取地址处存储的值
cout << ptr << endl; // 打印地址
ptr++;
}
cout << endl;
// 上面的处理指针向后移动了 数组元素数量 个 存储单位
ptr = ptr - 5;// 恢复 数组首地址的值
// 按照数组方式 使用[] 下标索引 获取数组元素
cout << "Using pointer index" << endl;
cout << "Value\tAddress" << endl;
for(int i = 0; i < arrLength; ++i)
{
cout << ptr[i] << "\t"; // 使用[] 下标索引 获取数组元素
cout << &ptr[i] << endl; // & 获取 元素 的存储地址===
}
delete [] ptr;// 释放 动态申请的内存
#### 2.2 列表List 动态内存的数组
// File : List.h =======================================================
#ifndef LIST_H
#define LIST_H
#include
class List // 类
{
private: // 私有 变量
int m_count; // 元素数量
int * m_items; // 首元素指针
public:
List(); // 类 构造函数
~List(); // 类 析构函数
// 获取指定索引处的值,因为不能简单的使用连续地址函数获取指定索引处的位置的元素值
int Get(int index);
// 在 指定索引 位置 插入元素,新建一个数组,旧数组元素赋值过来,在指定位置插入 新元素======
void Insert(int index, int val);
// 在链表中搜索指定元素 val
int Search(int val);
// 删除指定索引处的 元素,新建一个数量少1的数组,除指定元素外不复制
void Remove(int index);
// 统 计链表元素数量
int Count();
};
#endif // LIST_H
//List.c =====================================================================
// 在数组中插入一个元素,这里简单为创建一个新长度的数组,旧数组元素复制过来==
// 不过可以使用金蝉脱壳,每次多申请一些内存空间,容量不够了,再扩容=========
void List::Insert(int index, int val)
{
// 索引范围检查===
if(index < 0 || index > m_count)
return;
// 记录 旧数组首地址
int \* oldArray = m_items;
// 插入一个元素,数组元素数量+1
m_count++;
// 每次都 新分配一个 新数组
m_items = new int[m_count];
// Fill the new array with inserted data
for(int i=0, j=0; i < m_count; ++i)// i为 新数组索引,j为 旧数组索引
// i每次循环 必+1-----------------------------------
{
if(index == i)
{
m_items[i] = val; // 新插入的元素 放入指定 index 位置
}
else
{
m_items[i] = oldArray[j]; // 就数组元素 放到新数组中
++j; // 旧数组索引 ++ // j 为非指定索引处 才+1--------------------------
}
}
// 清空 旧数组 内存空间
delete [] oldArray;
}
// 删除指定索引处的元素,和插入的思想一致,创建一个新数组,除指定元素外不复制
void List::Remove(int index)
{
// 索引范围检查===
if(index < 0 || index > m_count)
return;
// 记录 旧数组首地址
int * oldArray = m_items;
// 删除一个元素,数量-1
m_count--;
// 初始化一个长度 较少1 的新数组
m_items = new int[m_count];
// 从旧数组 赋值 元素到新数组,除指定元素外不复制
for(int i=0, j=0; i < m_count; ++i, ++j)//i 新数组索引,j旧数组索引
// i,j 每次循环 必+1---
{
if(index == j)// 遍历到 旧数组中 指定 的 索引
{
++j; // 直接跳过该 位置 // 同时指定索引处,j还会 再次+1 跳过指定元素
}
m_items[i] = oldArray[j];// 旧数组元素 赋值 到 新数组元素
}
// 清空 旧数组 内存空间
delete [] oldArray;
}
// 完整实现
// https://github.com/Ewenwan/CPP-Data-Structures-and-Algorithms/blob/master/Chapter02/List/src/List.cpp
// 使用=====================
List list = List();
// 依次插入元素=====
list.Insert(0, 21);
list.Insert(1, 47);
list.Insert(2, 87);
list.Insert(3, 35);
list.Insert(4, 92);
// 打印元素=========
for(int i = 0; i < list.Count(); ++i)
{
cout << list.Get(i) << " ";
}
// 查找 87
cout << “Search element 71” << endl;
int result = list.Search(71);
if(result == -1) // 没找到 返回-1
cout << “71 is not found”;
else
cout << "71 is found at index " << result;
cout << endl << endl;
// 删除
list.Remove(2);
#### 2.3 节点链,关系网,朋友圈网,人脉圈,七大姑八大姨…
// 实现===================================
class Node // 节点类,嫌疑人
{
public:
int Value; // 嫌疑人信息,数据值,int类型
Node * Next; // 节点指向信息,人物关系
};
// 根据任务链信息,找出整个犯罪团伙===============
void PrintNode(Node * node)
{
// NULL 表明 线索到头了,幕后大佬后面没老虎了===
while(node != NULL)
{
cout << node->Value << " -> ";// 打印当前节点(嫌疑人)的信息(名字,脏污,财产)
node = node->Next; // 找到下一个嫌疑人=====
}
// 打印最后的 终止标志 NULL
cout << “NULL” << endl;
}
// 使用=============================
// ±-----±-----+
// | 7 | NULL |
// ±-----±-----+
// 节点1
Node * node1 = new Node;
node1->Value = 7;
// +------+------+
// | 14 | NULL |
// +------+------+
// 节点2
Node \* node2 = new Node;
node2->Value = 14;
// +------+------+
// | 21 | NULL |
// +------+------+
// 节点3
Node \* node3 = new Node;
node3->Value = 21;
// +------+------+ +------+------+ +------+------+
// | 7 | +---->| 14 | NULL | | 21 | NULL |
// +------+------+ +------+------+ +------+------+
// 节点1--->节点2
node1->Next = node2;
// +------+------+ +------+------+ +------+------+
// | 7 | +---->| 14 | +---->| 21 | NULL |
// +------+------+ +------+------+ +------+------+
// 节点1--->节点2--->节点3--->终止NULL
node2->Next = node3;
// 打印 节点链,找出人脉链,挖地三尺
PrintNode(node1);
// 节点链 模板Template 实现,可存储多种类型的数据==============================
template // template <typename *> 模板数据类型,任意数据类型
class Node
{
public:
T Value; // 模板类型数据
Node * Next; // 下一个节点 关系人物 模板类型节点
// 类构造函数======初始化两个内部数据===
Node(T value) : Value(value), Next(NULL) {}
};
// 打印函数也是用 模板类型=====
template
void PrintNode(Node * node)// 传入节点指针
{
// NULL 表明 线索到头了,幕后大佬后面没老虎了===
while(node != NULL)
{
cout << node->Value << " -> ";// 打印当前节点(嫌疑人)的信息(名字,脏污,财产)
node = node->Next; // 找到下一个嫌疑人=====
}
// 打印最后的 终止标志 NULL
cout << “NULL” << endl;
}
// 使用========================================
// ±-----±-----+
// | 4.93 | NULL |
// ±-----±-----+
// 节点1 浮点类型数据
Node * node1 = new Node(4.93);// 创建时,传入数据类型(模板类型具体化)
// +------+------+
// | 6.45 | NULL |
// +------+------+
// 节点2
Node<float> \* node2 = new Node<float>(6.45);
// +------+------+
// | 8.17 | NULL |
// +------+------+
// 节点3
Node<float> \* node3 = new Node<float>(8.17);
// +------+------+ +------+------+ +------+------+
// | 4.93 | +---->| 6.45 | NULL | | 8.17 | NULL |
// +------+------+ +------+------+ +------+------+
node1->Next = node2;
// +------+------+ +------+------+ +------+------+
// | 4.93 | +---->| 6.45 | +---->| 8.17 | NULL |
// +------+------+ +------+------+ +------+------+
// 节点1--->节点2--->节点3--->终止NULL
node2->Next = node3;
// Print the node
PrintNode(node1);
#### 2.4 单向链表
// File : Node.h 链表中的 单一节点实现,模板节点,可存储许多类型数据=================
#ifndef NODE_H
#define NODE_H
#include
// 模板节点,可存储许多类型数据
template
class Node
{
public:
T Value;
Node * Next;
// 类 构造函数 声明
Node(T value);
};
// 类构造函数实现
// 拿到外面的话,就需要在函数前面添加 Node:: 类名属性
template
Node::Node(T value) : Value(value), Next(NULL) {}
#endif // NODE_H
//==================================================
// File : LinkedList.h 链表实现,比 节点链 多一些功能===========================
#include “Node.h” // 单个模板节点
// 模板链表==================
template
class LinkedList
{
private: // private 私有变量===
int m_count; // 实际节点数量
public: // 公开方法====
// The first node in the list or null if empty
Node * Head; // 链表表头节点
// The last node in the list or null if empty
Node<T> \* Tail; // 链表表尾节点
// 类构造函数 Constructor
LinkedList();
// 获取第 index 个 节点 Get() operation
Node<T> \* Get(int index);
// 在链表中 插入节点 的操作===Insert() operation
void InsertHead(T val);// 头部插入节点
void InsertTail(T val);// 尾部插入节点
void Insert(int index, T val);// 插入节点
// 在链表中查找指定的值 Search() operation
int Search(T val);
// 删除节点的操作 ==Remove() operation===
void RemoveHead();// 去除表头节点
void RemoveTail();// 去除表尾节点
void Remove(int index);// 去 链条中的节点
// 附加操作======
int Count(); // 节点数量 统计
void PrintList();// 打印链表中的每一个节点的信息====
};
// 类 方法的实现方法 直接在 头文件中实现,比放在另一个cpp文件中好=========
//=================================================
// head … tail
//index 0 1 2
// ±-----±-----+ ±-----±-----+ ±-----±-----+
// | 4.93 | ±—>| 6.45 | ±—>| 8.17 | NULL |
// ±-----±-----+ ±-----±-----+ ±-----±-----+
// 前置节点 目标节点 后置节点
// prevNode node nextNode
// 对目标索引位置 进行 插入/删除 操作时,先找到 目标节点及其前后位置的 前置节点 和 后置节点
//=================================================
// 头部插入节点=======================
template
void LinkedList::InsertHead(T val)
{
// 新建一个节点====================
Node * node = new Node(val);
// 新节点的后继 指向原首节点
node->Next = Head;
// 新节点重置为 首节点
Head = node;
// 仅有一个节点时,尾节点==首节点
if(m_count == 0)
Tail = Head;
// One element is added
m_count++;
}
// 尾部插入节点=======================
template
void LinkedList::InsertTail(T val)
{
// 链表为空时,和从头部插入节点一致===
if(m_count == 0)
{
InsertHead(val);
return;
}
// 新建一个节点
Node<T> \* node = new Node<T>(val);
// 原链表的后继 设置为 新节点
Tail->Next = node;
// 新节点重置为 尾节点
Tail = node;
// 数量++
m_count++;
}
// 在指定位置处插入节点======================
template
void LinkedList::Insert(int index, T val)
{
// 检查位置index的合理性=
if(index < 0 || index > m_count)
return;
// 头部插入的情况=========
if(index == 0)
{
InsertHead(val);
return;// 直接返回
}
// 尾部插入的情况=========
else if(index == m_count)
{
InsertTail(val);
return;// 直接返回
}
// 链条中间插入 节点的情况===
// 从首节点开始 遍历到 指定位置处的 前一个节点 (找到前置节点)
Node<T> \* prevNode = Head;
// 找到 前置节点============ 断开处的 前端
for(int i = 0; i < index - 1; ++i)
{
prevNode = prevNode->Next;
}
// 指定位置的(后置节点)==== 断开处的 后端
Node<T> \* nextNode = prevNode->Next;
// 创建一个新节点==================
Node<T> \* node = new Node<T>(val);
// 新节点后继 指向 后置节点
node->Next = nextNode;
// 前置节点 后继 指向 新节点
prevNode->Next = node;
// 数量++
m_count++;
}
// 去除头部节点======================
template
void LinkedList::RemoveHead()
{
// 链表 是否为空 检查
if(m_count == 0)
return;
// 原 头部节点
Node<T> \* node = Head;
// 原 头部节点的后继作为 新 首节点
Head = Head->Next;
// 删除原首节点
delete node;
// 仅有一个节点时,尾节点==首节点====
if(m_count == 1)
Tail = Head;// 新添加=========修复bug=====
// 数量--
m_count--;
}
// 去除尾部节点=========================
template
void LinkedList::RemoveTail()
{
// 链表 是否为空 检查
if(m_count == 0)
return;
// 当链表数量为1时,和去除头部节点一致
if(m_count == 1)
{
RemoveHead();
return;
}
// 从头节点开始,遍历到尾节点 的 前置节点,因为不能反向遍历,所以需要从头部向后遍历
Node<T> \* prevNode = Head;
// 需要删除的节点
Node<T> \* node = Head->Next;
// 遍历 找到指定的两个节点
while(node->Next != NULL)// 注意是 需要删除的节点 的后继 不为 NULL
{
prevNode = prevNode->Next;// 前置节点
node = node->Next; // 需要删除的节点,即原 尾节点
}
// 原尾节点的 前置节点 需要 变成 新的 尾节点
prevNode->Next = NULL; // 尾节点的后继 为 NULL
Tail = prevNode; // 前置节点 重置为 尾节点
// 删除原 尾节点
delete node;
// 数量--
m_count--;
}
// 删除指定索引位置的 节点
template
void LinkedList::Remove(int index)
{
// 链表 是否为空 检查============
if(m_count == 0)
return;
// 检查指定位置是否合理===========
if(index < 0 || index >= m_count)
return;
// 删除头部的节点=============
if(index == 0)
{
RemoveHead();
return;// 直接返回
}
//删除尾部的节点==============
else if(index == m_count - 1)
{
RemoveTail();
return;// 直接返回
}
// 从 头部节点 开始 遍历
Node<T> \* prevNode = Head;
// 找到指定 索引 前面的 前置节点
for(int i = 0; i < index - 1; ++i)// 到index-2
{
prevNode = prevNode->Next; // 前置节点 index-2 位置
}
// 指定节点
Node<T> \* node = prevNode->Next;// index-1 位置
// 后置节点
Node<T> \* nextNode = node->Next;// index 位置 从0开始
// 前置节点 的后继 设置为后置节点 跳过中间的 指定删除的节点
prevNode->Next = nextNode;
// 删除指定节点
delete node;
// 数量--
m_count--;
}
// 使用=================================================
// NULL 创建一个空 链表 传入模板类型============
LinkedList linkedList = LinkedList();
// 头部插入======================
// 43->NULL
linkedList.InsertHead(43);
// 76->43->NULL
linkedList.InsertHead(76);
// 尾部插入======================
// 76->43->15->NULL
linkedList.InsertTail(15);
// 76->43->15->44->NULL
linkedList.InsertTail(44);
// 中间插入======================
// 76->43->15->44->100->NULL
linkedList.Insert(4, 100);
// 76->43->15->48->44->100->NULL
linkedList.Insert(3, 48);
// 22->76->43->15->48->44->100->NULL
linkedList.Insert(0, 22);
// 删除节点=====================
linkedList.Remove(0);// Remove first element
// 76->43->15->48->44->100->NULL
linkedList.Remove(4);// Remove fifth element
// 76->43->15->48->100->NULL
linkedList.Remove(9);// Remove tenth element
// Nothing happen
// 76->43->15->48->100->NULL
#### 2.5 双向链表
![img](https://img-blog.csdnimg.cn/img_convert/d1da9bfb147b991d439e9736068db722.png)
![img](https://img-blog.csdnimg.cn/img_convert/7c2a8115b039395f7e93d5f6f1632b2f.png)
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
入======================
// 43->NULL
linkedList.InsertHead(43);
// 76->43->NULL
linkedList.InsertHead(76);
// 尾部插入======================
// 76->43->15->NULL
linkedList.InsertTail(15);
// 76->43->15->44->NULL
linkedList.InsertTail(44);
// 中间插入======================
// 76->43->15->44->100->NULL
linkedList.Insert(4, 100);
// 76->43->15->48->44->100->NULL
linkedList.Insert(3, 48);
// 22->76->43->15->48->44->100->NULL
linkedList.Insert(0, 22);
// 删除节点=====================
linkedList.Remove(0);// Remove first element
// 76->43->15->48->44->100->NULL
linkedList.Remove(4);// Remove fifth element
// 76->43->15->48->100->NULL
linkedList.Remove(9);// Remove tenth element
// Nothing happen
// 76->43->15->48->100->NULL
2.5 双向链表
[外链图片转存中…(img-7lB3K3M4-1715736557857)]
[外链图片转存中…(img-Qm7kZBDi-1715736557857)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!