C++数据结构和算法1 c++基础 枚举 结构体 抽象数据结构-类 模板函数、模板类 数组 列表 单向链表 双向链表_c(2)

img
img

既有适合小白学习的零基础资料,也有适合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行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值