数据结构与算法---线性表

news2024/11/23 23:11:32

线性表

1.顺序表

需求分析

/*
	创建顺序表

	具体功能:
		初始化顺序表
		销毁顺序表
		获取顺序表元素个数
		输出顺序表中的内容
		自动扩容

		增 --- 插入数据(包含了尾部添加功能)
		删 --- 删除数据(包含了尾部删除功能)
		改 --- 修改数据
		查 --- 查找数据

		尾部追加
		尾部删除
 */

C语言实现

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>


// 定义顺序表存储的数据类型
typedef int dataType;


// 定义顺序表结构
typedef struct SeqList {
	dataType* arr;	// 用来记录表的地址
	int capacity;	// 用来记录表的容量
	int size;		// 用来记录表中元素的个数
}SeqList;


// 功能声明:
// ----------------------------------------------------
bool initList(SeqList&, int);				// 初始化顺序表
void destroyList(SeqList&);					// 销毁顺序表
int sizeList(SeqList&);						// 获取顺序表元素个数
void printList(SeqList&);					// 输出顺序表中的内容
bool expandList(SeqList&, int);				// 自动扩容
// ----------------------------------------------------
bool insertList(SeqList&, dataType, int);		// 增
bool deleteList(SeqList&, int);					// 删
bool modifyList(SeqList&, dataType, int);		// 改
int findList(SeqList&, dataType);				// 查
// ----------------------------------------------------
bool appendList(SeqList&, dataType);	// 尾部追加数据 --- 增的扩展
bool popList(SeqList&);					// 删除尾部数据 --- 删的扩展
// ----------------------------------------------------



int main()
{
	// 创建顺序表
	SeqList myList;

	// 初始化顺序表
	bool res = initList(myList, 5);		// 指定顺序表的数据空间为5个
	(res == true) ? printf("顺序表初始化成功!\n") : printf("顺序表初始化失败!\n");

	// 获取顺序表元素个数
	int size = sizeList(myList);
	printf("顺序表中元素的个数:%d\n", size);

	// 输出顺序表中的内容
	printList(myList);

	// 插入数据
	insertList(myList, 10, 0);
	insertList(myList, 20, 0);
	insertList(myList, 30, 0);
	insertList(myList, 40, 0);
	printList(myList);

	// 删除数据
	deleteList(myList, 2);			// 删除顺序表中下标为2的元素
	printList(myList);

	// 修改数据
	modifyList(myList, 66, 2);		// 将顺序表中下标为2的元素修改为66
	printList(myList);

	// 查找数据
	int searchTarget = 40;
	int index = findList(myList, searchTarget);
	printf("元素%d的下标:%d\n", searchTarget, index);

	// 尾部追加
	appendList(myList, 50);
	printList(myList);

	// 尾部删除
	popList(myList);
	printList(myList);

	// 销毁顺序表
	destroyList(myList);

	char justPause = getchar();		// 让程序暂停一下
	return 0;
}


// 功能实现:
// ----------------------------------------------------
// 初始化顺序表
bool initList(SeqList& sl, int capacity)
{
	// 开辟空间,形成一个表,并记录表的地址
	sl.arr = (dataType*)malloc(sizeof(dataType) * capacity);
	if (sl.arr == NULL)	return false;	// 开辟空间失败

	// 其他初始化操作
	sl.capacity = capacity;		// 初始化表的容量
	sl.size = 0;				// 初始化表中元素的个数
	return true;
}

// 销毁顺序表
void destroyList(SeqList& sl)
{
	free(sl.arr);		// 释放内存空间
	sl.arr = NULL;
	sl.size = 0;
	sl.capacity = 0;
}

// 获取顺序表元素个数
int sizeList(SeqList& sl)
{
	return sl.size;
}

// 输出顺序表中的内容
void printList(SeqList& sl)
{
	printf("[ ");
	for (int i = 0; i < sl.size; i++)
	{
		printf("%d, ", sl.arr[i]);
	}
	printf("]\n");
}

// 自动扩容
bool expandList(SeqList& sl, int size)
{
	// 开辟一片新内存空间
	dataType* p = (dataType*)malloc(sizeof(dataType) * (sl.capacity + size));
	if (sl.arr == NULL)	return false;		// 扩容失败

	// 开辟成功,将数据迁移到新的空间
	for (int i = 0; i < sl.size; i++)
	{
		p[i] = sl.arr[i];
	}

	// 释放原来的空间
	free(sl.arr);

	// 更新数据
	sl.capacity += size;
	sl.arr = p;
	p = NULL;

	return true;
}

// ----------------------------------------------------

// 插入数据
bool insertList(SeqList& sl, dataType element, int index)
{
	// 判断下标是否合法
	if (index < 0 || index > sl.size)	return false;

	// 判断顺序表是否已经满了,如果满了,进行扩容操作
	if (sl.size == sl.capacity)
	{
		if (expandList(sl, 10) == false)	return false;	// 扩容:10个数据空间
	}

	// 元素迁移
	for (int i = sl.size; i > index; --i)
	{
		sl.arr[i] = sl.arr[i - 1];
	}

	// 在目标位置插入元素
	sl.arr[index] = element;

	// 更新表中元素的个数
	sl.size++;

	return true;
}

// 删除数据
bool deleteList(SeqList& sl, int index)
{
	// 判断表是否为空
	if (sl.size == 0)	return false;

	// 判断插入的下标是否合法
	if (index < 0 || index > sl.size - 1)	return false;

	// 数据覆盖
	for (int i = index; i < sl.size - 1; i++)
	{
		sl.arr[i] = sl.arr[i + 1];
	}

	// 更新数据
	sl.size--;	// 这里实现了逻辑删除,而不是实际删除,因为也没有必要进行实际删除

	return true;
}

// 修改数据
bool modifyList(SeqList& sl, dataType element, int index)
{
	// 判断插入的下标是否合法
	if (index < 0 || index > sl.size - 1)		return false;

	// 修改数据
	sl.arr[index] = element;
	return true;
}

// 查找数据
int findList(SeqList& sl, dataType element)
{
	for (int i = 0; i < sl.size; i++)
	{
		if (sl.arr[i] == element)		return i;
	}
	return -1;		// 查找不到元素,返回-1
}

// ----------------------------------------------------

// 尾部追加
bool appendList(SeqList& sl, dataType element)
{
	return insertList(sl, element, sl.size);
}

// 尾部删除
bool popList(SeqList& sl)
{
	return deleteList(sl, sl.size - 1);
}

C++实现

#include <iostream>


// 定义顺序表类
template<class T>	// 顺序表存储的数据类型为T
class SeqList
{
private:
	// 顺序表的属性:
	T* arr;			// 记录表的地址
	int capacity;	// 记录表的容量
	int size;		// 记录表中元素的个数

public:
	// 顺序表提供的方法(类内声明)
	// ----------------------------------------------------
	SeqList();							// 初始化顺序表
	~SeqList();							// 销毁顺序表
	int sizeList();						// 获取顺序表元素个数
	void printList();					// 输出顺序表中的内容
	bool expandList();					// 自动扩容
	// ----------------------------------------------------
	bool insertList(T, int);		// 增
	bool deleteList(int);			// 删
	bool modifyList(T, int);		// 改
	int findList(T);				// 查
	// ----------------------------------------------------
	bool appendList(T);			// 尾部追加数据 --- 增的扩展
	bool popList();				// 删除尾部数据 --- 删的扩展
	// ----------------------------------------------------
};



int main()
{
	// 创建顺序表 + 初始化顺序表
	SeqList<int> sl;

	// 获取顺序表元素个数
	int size = sl.sizeList();
	printf("顺序表中元素的个数:%d\n", size);

	// 输出顺序表中的内容
	sl.printList();

	// 插入数据
	sl.insertList(10, 0);
	sl.insertList(20, 0);
	sl.insertList(30, 0);
	sl.insertList(40, 0);
	sl.printList();

	// 删除数据
	sl.deleteList(2);		// 删除顺序表中下标为2的元素
	sl.printList();

	// 修改数据
	sl.modifyList(66, 2);	// 将顺序表中下标为2的元素修改为66
	sl.printList();

	// 查找数据
	int searchTarget = 40;
	int index = sl.findList(searchTarget);
	printf("元素%d的下标:%d\n", searchTarget, index);

	// 尾部追加
	sl.appendList(50);
	sl.printList();

	// 尾部删除
	sl.popList();
	sl.printList();

	// 销毁顺序表
	// 不用手动销毁,因为对象被回收时会自动调用析构函数

	system("pause");		// 让程序暂停一下
	return 0;
}


// 顺序表提供的方法(类外实现)
// ----------------------------------------------------
// 初始化顺序表
template<class T>
SeqList<T>::SeqList()
{
	this->arr = new T[capacity];		// 创建表空间
	this->capacity = capacity;			// 记录表的容量
	this->size = 0;						// 记录表中元素的个数
}

// 销毁顺序表
template<class T>
SeqList<T>::~SeqList()
{
	delete this->arr;		// 释放表空间
	this->capacity = 0;		// 容量大小置空
	this->size = 0;			// 元素个数置空
}

// 获取顺序表元素个数
template<class T>
int SeqList<T>::sizeList()
{
	return this->size;
}

// 输出顺序表中的内容
template<class T>
void SeqList<T>::printList()
{
	std::cout << "[ ";
	for (int i = 0; i < this->size; i++)
	{
		std::cout << this->arr[i] << ", ";
	}
	std::cout << "]" << std::endl;
}

// 自动扩容
template<class T>
bool SeqList<T>::expandList()
{
	// 开辟新的内存空间
	T* temp = new T[this->capacity + 10];	// 每次扩容10个空间
	if (temp == nullptr)	return false;

	// 将数据迁移到新的内存空间
	for (int i = 0; i < this->size; i++)
	{
		temp[i] = this->arr[i];
	}

	// 释放原来的空间
	delete this->arr;

	// 更新数据
	this->arr = temp;
	this->capacity += size;
	temp = nullptr;
	return true;
}

// ----------------------------------------------------

// 插入数据
template<class T>
bool SeqList<T>::insertList(T element, int index)
{
	// 判断下标是否合法
	if (index < 0 || index > this->size)	return false;

	// 判断顺序表是否已经满了,如果满了,进行扩容操作
	if (this->size == this->capacity)	expandList();

	// 元素迁移
	for (int i = size; i > index; i--)
	{
		this->arr[i] = this->arr[i - 1];
	}

	// 在目标位置插入元素
	this->arr[index] = element;

	// 更新数据
	this->size++;

	return true;
}

// 删除数据
template<class T>
bool SeqList<T>::deleteList(int index)
{
	// 判断下标是否合法
	if (index < 0 || index > this->size - 1)	return false;

	// 数据覆盖
	for (int i = index; i < this->size - 1; i++)
	{
		this->arr[i] = this->arr[i + 1];
	}

	// 更新数据
	this->size--;

	return true;
}

// 修改数据
template<class T>
bool SeqList<T>::modifyList(T element, int index)
{
	// 判断下标是否合法
	if (index < 0 || index > this->size - 1)	return false;

	// 修改数据
	this->arr[index] = element;

	return true;
}

// 查找数据
template<class T>
int SeqList<T>::findList(T element)
{
	for (int i = 0; i < this->size; i++)
	{
		if (this->arr[i] == element)	return i;
	}
	return -1;		// 查找不到结果,返回-1
}

// ----------------------------------------------------

// 尾部追加
template<class T>
bool SeqList<T>::appendList(T element)
{
	return insertList(element, this->size);
}

// 尾部删除
template<class T>
bool SeqList<T>::popList()
{
	return deleteList(this->size - 1);
}

2.链表

需求分析

/*
	创建链表

	具体功能:
		初始化链表
		销毁链表
		获取链表元素个数
		输出链表中的内容

		插入数据
		删除数据
		修改数据
		查找数据

		尾部追加
		尾部删除
 */

C语言实现

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>


// 数据类型
typedef int dataType;


// 节点的结构
typedef struct Node
{
	dataType data;		// 用来存放数据
	Node* next;			// 用来存放下一个节点的内存地址
}Node;


// // -------------------------- 功能声明 --------------------------
void init(Node*);
int size(Node*);
void print(Node*);
bool insert(Node*, dataType, int);
bool remove(Node*, int);
bool modify(Node*, dataType, int);
int find(Node*, dataType);
bool append(Node*, dataType);
bool pop(Node*);
void destroy(Node*);

int main()
{
	// 创建链表 (创建一个头节点)
	Node headNode;

	// 初始化链表 (初始化头节点)
	init(&headNode);

	// 获取链表元素个数
	printf("链表元素的个数:%d\n", size(&headNode));

	// 输出链表中的内容
	print(&headNode);

	// 插入数据
	insert(&headNode, 66, 1);
	insert(&headNode, 77, 1);
	insert(&headNode, 88, 1);
	print(&headNode);

	// 删除数据
	remove(&headNode, 1);
	print(&headNode);

	// 修改数据
	modify(&headNode, 99, 0);
	print(&headNode);

	// 查找数据
	int index = find(&headNode, 66);
	(index == -1) ? printf("查找不到此数据!\n") : printf("查到此数据的下标:%d\n", index);

	// 尾部追加
	append(&headNode, 6666);
	print(&headNode);

	// 尾部删除
	pop(&headNode);
	print(&headNode);

	// 销毁链表
	destroy(&headNode);

	char justPause = getchar();		// 让程序暂停
	return 0;
}

// -------------------------- 功能实现 --------------------------
// 初始化链表
void init(Node* node)
{
	node->next = NULL;
}

// 获取链表元素个数
int size(Node* node)
{
	// 默认就有1个元素 (即:头节点)
	int size = 1;

	// node 是一个整体,请把 node->next 也看作是一个整体,如果 node->next 这个整体不为 NULL,说明这个整体对应的空间有数据(元素)!!
	while (node->next)
	{
		size++;
		node = node->next;
	}
	return size;
}

// 输出链表中的内容
void print(Node* node)
{
	printf("(*) -> ");
	while (node->next)
	{
		node = node->next;
		printf("%d -> ", node->data);
	}
	printf("\n");
}

// 插入数据
bool insert(Node* node, dataType element, int index)
{
	// 检查下标是否合法 (检查左边界)
	if (index < 1)	return false;

	// 根据index确定步长,将node更新(移动)对应的次数
	// 更新(移动)结束后,node关联的就是要被插的节点的上一个节点
	while (--index)
	{
		node = node->next;
		if (node == NULL)	return false;
	}

	// 将数据放到新节点中
	Node* temp = (Node*)malloc(sizeof(Node));	// 申请一块内存作为新节点
	if (temp == NULL)	return false;			// 申请内存空间失败
	temp->data = element;	// 在新节点里面存放要插入的数据

	// 完成节点的插入 (下面代码顺序不可替换!!)
	temp->next = node->next;
	node->next = temp;

	return true;
}

// 删除数据
bool remove(Node* node, int index)
{
	// 检查下标是否合法 (检查左边界)
	if (index < 1)	return false;

	// 根据index确定步长,将node更新(移动)对应的次数
	// 更新(移动)结束后,node关联的就是要被删除的节点的上一个节点
	while (--index)
	{
		node = node->next;
		if (node == NULL)	return false;
	}

	// 删除节点
	Node* temp = node->next;			// 先引用一下待会将要被删除的节点,防止丢失内存地址而无法真正删除
	node->next = node->next->next;		// 实现逻辑删除
	free(temp);							// 释放内存空间,实现了真正的删除,并且回收了资源

	return true;
}

// 修改数据
bool modify(Node* node, dataType element, int index)
{
	// 检查下标是否合法 (检查左边界)
	if (index < 1)	return false;

	// 根据index确定步长,将node更新(移动)对应的次数
	// 更新(移动)结束后,node关联的就是要被修改的节点的上一个节点
	while (--index)
	{
		node = node->next;
		if (node == NULL)	return false;
	}

	// 修改数据
	node->next->data = element;

	return true;
}

// 查找数据
int find(Node* node, dataType element)
{
	int index = 0;		// 头节点的下标为0,其他节点的下标可以在此基础上通过累加计算得到
	while (node->next)
	{
		node = node->next;
		index++;
		if (node->data == element)	return index;	// 找到了数据,返回对应的下标号
	}
	return -1;		// 找不到数据,返回-1
}

// 尾部追加
bool append(Node* node, dataType element)
{
	// 一直循环,直到 node->next 整体为NULL为止
	// 循环结束后,此时的 node 关联着最后一个节点
	while (node->next)
	{
		node = node->next;
	}

	Node* temp = (Node*)malloc(sizeof(Node));	// 申请内存空间,制作新节点
	if (temp == NULL)	return false;			// 申请失败

	// 将数据放到到新节点中
	temp->data = element;
	temp->next = NULL;

	// 尾节点指向新节点
	node->next = temp;

	return true;
}

// 尾部删除
bool pop(Node* node)
{
	// 如果这个链表只有头节点,而没有后面的数据节点:
	if (node->next == NULL)	return false;

	// 如果有数据节点:
	// 一直循环,直到 node->next 整体为NULL为止
	// 循环结束后,此时的 node 关联的是最后一个节点,而 prev 则关联着倒数第二个节点
	Node* prev = NULL;
	while (node->next)
	{
		prev = node;		// 先记录旧的node
		node = node->next;	// 再创建新的node
	}

	// 释放最后一个节点的内存
	free(node);

	// 将倒数第二个节点的next指向NULL
	prev->next = NULL;

	return true;
}

// 销毁链表
void destroy(Node* node)
{
	// 释放头节点以外的所有节点的内存空间,堆区的空间
	// 注意:不可手动释放头节点的内存空间,因为它是main主函数的变量,栈区里面的变量
	Node* temp = NULL;
	while (node->next)
	{
		temp = node->next;	// 先备份一下节点的指针
		node->next = node->next->next;
		free(temp);
	}
}

C++实现

#include<iostream>


// 节点
template <class T>
class Node
{
public:
	T data;				// 用来存放数据
	Node<T>* next;		// 用来存放下一个节点的内存地址

	// 构造函数
	Node()
	{
		this->next = nullptr;
	}

	// 析构函数
	~Node()
	{
		this->next = nullptr;
	}
};


// 链表
template<class T = int>		// 默认模板参数为int类型
class Link
{
private:
	Node<T>* head;		// 用来记录头节点指针
	int size;			// 用来记录链表中元素的个数

public:
	// -------------------------- 功能类内声明 --------------------------
	Link();
	~Link();
	int getSize();
	void printLink();
	bool insert(T, int);
	bool remove(int);
	bool modify(T, int);
	int find(T);
	bool append(T);
	bool pop();
};



int main()
{
	// 创建链表 + 初始化链表
	Link<> myLink;

	// 获取链表元素个数
	printf("链表元素的个数:%d\n", myLink.getSize());

	// 输出链表中的内容
	myLink.printLink();

	// 插入数据
	myLink.insert(66, 1);
	myLink.insert(77, 1);
	myLink.insert(88, 1);
	myLink.insert(99, 1);
	myLink.printLink();

	// 删除数据
	myLink.remove(1);
	myLink.printLink();

	// 修改数据
	myLink.modify(100, 2);
	myLink.printLink();

	// 查找数据
	int index = myLink.find(66);
	(index == -1) ? printf("查找不到此数据!\n") : printf("查到此数据的下标:%d\n", index);

	// 尾部追加
	myLink.append(1024);
	myLink.printLink();

	// 尾部删除
	myLink.pop();
	myLink.printLink();

	// 销毁链表
	// 自动会调用析构函数去销毁链表,无需手动操作

	system("pause");	// 让程序暂停
	return 0;
}


// -------------------------- 功能类外实现 --------------------------
// 初始化链表
template<class T>
Link<T>::Link()
{
	this->head = new Node<T>;	// 创建一个头节点,并让 this->head 能够指向这个头节点
	this->size = 1;				// 链表元素个数
}

// 销毁链表
template<class T>
Link<T>::~Link()
{
	// 释放其他节点
	Node<T>* temp = nullptr;
	while (this->head->next)	// 判断头节点的下一个节点是否为空,如果不为空,说明节点里面有数据,需要删除这个节点
	{
		temp = this->head->next;	// 先备份好内存地址,方便待会删除这个地址所指向的节点
		this->head->next = this->head->next->next;	// 将头节点连接"要被删除节点"的下一个节点
		delete temp;	// 删除节点
	}

	// 释放头节点
	delete this->head;
	this->head = nullptr;

	// 链表元素个数置零
	this->size = 0;
}

// 获取链表元素个数
template<class T>
int Link<T>::getSize()
{
	return this->size;
}

// 输出链表中的内容
template<class T>
void Link<T>::printLink()
{
	Node<T>* temp = this->head->next;	// 头节点的下一个节点
	std::cout << "(*) -> ";
	while (temp)	// 如果 temp 不是 nullptr 空指针,则说明当前节点有数据,可以进入循环内部,输出数据
	{
		std::cout << temp->data << " -> ";
		temp = temp->next;
	}
	std::cout << std::endl;
}

// 插入数据
template<class T>
bool Link<T>::insert(T data, int index)
{
	// 检查下标是否合法,可插入的范围是 [1, this->size]
	if (index < 1 || index > this->size)	return false;

	// 获取目标节点的上一个节点
	Node<T>* targetNodePre = this->head;
	for (int i = 0; i < index - 1; i++)
	{
		targetNodePre = targetNodePre->next;
	}

	// 创建新节点,并将数据存放到里面
	Node<T>* newNode = new Node<T>;
	newNode->data = data;

	// 将新节点插入到链表中
	newNode->next = targetNodePre->next;
	targetNodePre->next = newNode;

	// 更新元素个数
	this->size++;

	return true;
}

// 删除数据
template<class T>
bool Link<T>::remove(int index)
{
	// 检查下标是否合法,可删除的范围是 [1, this->size -1]
	if (index < 1 || index > this->size)	return false;

	// 获取目标节点的上一个节点
	Node<T>* targetNodePre = this->head;
	for (int i = 0; i < index - 1; i++)
	{
		targetNodePre = targetNodePre->next;
	}

	// 删除节点
	Node<T>* temp = targetNodePre->next;	// 先引用一下待会将要被删除的节点,防止丢失内存地址而无法真正删除
	targetNodePre->next = targetNodePre->next->next;	// 实现逻辑删除
	delete temp;	// 释放内存空间,实现了真正的删除,并且回收了资源

	// 更新元素个数
	this->size--;

	return true;
}

// 修改数据
template<class T>
bool Link<T>::modify(T data, int index)
{
	// 检查下标是否合法,可修改的范围是 [1, this->size -1]
	if (index < 1 || index > this->size)	return false;

	// 获取目标节点的上一个节点
	Node<T>* targetNodePre = this->head;
	for (int i = 0; i < index - 1; i++)
	{
		targetNodePre = targetNodePre->next;
	}

	// 修改数据
	targetNodePre->next->data = data;

	return true;
}

// 查找数据
template<class T>
int Link<T>::find(T data)
{
	int index = 0;		// 头节点的下标为0,其他节点的下标可以在此基础上通过累加计算得到
	Node<T>* targetNodePre = this->head;
	while (targetNodePre->next)		// 如果不为空指针nullptr,说明里面有数据
	{
		targetNodePre = targetNodePre->next;
		index++;
		if (targetNodePre->data == data)	return index;	// 找到了数据,返回对应的下标号
	}
	return -1;		// 找不到数据,返回-1
}

// 尾部追加
template<class T>
bool Link<T>::append(T data)
{
	return insert(data, this->size);
}

// 尾部删除
template<class T>
bool Link<T>::pop()
{
	return remove(this->size - 1);
}

3.扩展

双向链表

/*
	C++实现双向链表:
	  1.插入数据
	  2.删除数据
	  3.展示数据
*/

#include<iostream>


// 节点
template<class T>
class Node
{
public:
	T data;
	Node* next;
	Node* prev;

	Node()
	{
		this->next = nullptr;
		this->prev = nullptr;
	}

	~Node()
	{
		this->next = nullptr;
		this->prev = nullptr;
	}
};


// 链表
template<class T = int>
class Link
{
private:
	Node<T>* head;
	int size;

public:
	Link()
	{
		this->head = new Node<T>;
		this->size = 1;
	}

	~Link()
	{
		// 释放其他节点
		Node<T>* temp = nullptr;
		while (this->head->next)
		{
			temp = this->head->next;
			this->head->next = this->head->next->next;
			delete temp;
		}

		// 释放头节点
		delete this->head;
		this->head = nullptr;
		this->size = 0;
	}

	bool insert(T data, int index)
	{
		// 下标合法性校验
		if (index < 1 || index > this->size)	return false;

		// 获取目标节点的前驱节点
		Node<T>* targetNodePre = this->head;
		for (int i = 1; i < index; i++)
		{
			targetNodePre = targetNodePre->next;
		}

		// 创建新节点,并装入数据
		Node<T>* newNode = new Node<T>;
		newNode->data = data;

		// 将新节点插入到链表中		[...targetNodePre <===> targetNodePre->next] <--- newNode
		newNode->next = targetNodePre->next;
		newNode->prev = targetNodePre;
		if (targetNodePre->next != nullptr)	targetNodePre->next->prev = newNode;
		targetNodePre->next = newNode;

		// 更新节点个数
		this->size++;

		return true;
	}

	bool remove(int index)
	{
		// 下标合法性校验
		if (index < 1 || index > this->size - 1)	return false;

		// 获取目标节点
		Node<T>* targetNode = this->head;
		for (int i = 1; i <= index; i++)
		{
			targetNode = targetNode->next;
		}

		// 删除操作	[targetNode->prev <===> targetNode <===> targetNode->next]
		if (targetNode->next != nullptr)	targetNode->next->prev = targetNode->prev;
		targetNode->prev->next = targetNode->next;
		delete targetNode;

		// 更新节点个数
		this->size--;

		return true;
	}

	void printLink()
	{
		std::cout << "(*) <==> ";
		Node<T>* temp = this->head;
		while (temp->next)
		{
			temp = temp->next;
			std::cout << temp->data << " <==> ";
		}
		std::cout << std::endl;
	}
};


// 主函数
int main()
{
	// 创建链表并初始化
	Link<int> myLink;
	myLink.printLink();

	// 插入数据
	myLink.insert(10, 1);
	myLink.printLink();

	myLink.insert(20, 2);
	myLink.printLink();

	myLink.insert(30, 3);
	myLink.printLink();

	// 删除数据
	myLink.remove(1);
	myLink.printLink();

	myLink.remove(1);
	myLink.printLink();

	myLink.remove(1);
	myLink.printLink();

	system("pause");
	return 0;
}

循环链表

在这里插入图片描述

特殊线性表

1.栈

通过顺序表实现

// C++

#include<iostream>
#include<string>
using namespace std;


template<class T>
class Stack
{
public:
	T* arr;			// 栈空间
	int capacity;	// 栈的容量
	int top;		// 用于记录栈顶的位置

	Stack()
	{
		this->arr = new T[10];		// 开辟空间
		this->capacity = 10;
		this->top = -1;
	}

	~Stack()
	{
		delete[] this->arr;			// 释放空间
		this->capacity = 0;
		this->top = -1;
	}

	// 入栈
	Stack& push(T data)
	{
		top++;
		this->arr[top] = data;
		return *this;
	}

	// 出栈
	Stack& pop()
	{
		top--;
		return *this;
	}

	// 输出栈里面的内容
	void show()
	{
		string symbol = "";
		for (int i = 0; i <= top; i++)
		{
			symbol += "----";
		}
		cout << "*" << symbol << endl << "| ";
		for (int i = 0; i <= top; i++)
		{
			std::cout << this->arr[i] << "  ";
		}
		cout << endl << "*" << symbol << endl << endl;
	}
};


int main()
{
	Stack<int> s;

	// 入栈
	s.push(10);
	s.push(20);
	s.push(30).show();

	// 出栈
	s.pop().show();
	s.pop().show();
	s.pop().show();

	system("pause");
	return 0;
}

通过链表实现

// C++

#include<iostream>
#include<string>
using namespace std;


// 节点
template<class T>
class Node
{
public:
	T data;
	Node* next;

	Node()
	{
		this->next = nullptr;
	}
};


// 栈(通过链表实现的栈)
template<class T>
class Stack
{
public:
	Node<T>* head;		// 头节点
	int size;			// 用于记录栈中的元素个数

	Stack()
	{
		this->head = new Node<T>;	// 创建头节点
		this->size = 0;
	}

	~Stack()
	{
		// 释放其他节点
		Node<T>* temp = nullptr;
		while (this->head->next)
		{
			temp = this->head->next;
			this->head->next = this->head->next->next;
			delete temp;
		}

		// 释放头节点
		delete this->head;
		this->head = nullptr;
		this->size = 0;
	}

	// 入栈
	Stack& push(T data)
	{
		// 创建新节点,并存放数据
		Node<T>* newNode = new Node<T>;
		newNode->data = data;

		// 插入新节点
		newNode->next = this->head->next;
		this->head->next = newNode;

		// 更新元素个数
		size++;

		return *this;
	}

	// 出栈
	Stack& pop()
	{
		// 删除节点
		Node<T>* temp = nullptr;
		if (this->head->next)
		{
			temp = this->head->next;
			this->head->next = this->head->next->next;
			delete temp;
		}

		// 更新元素个数
		size--;

		return *this;
	}

	// 输出栈里面的内容
	void show()
	{
		string symbol = "";
		for (int i = 0; i < this->size; i++)
		{
			symbol += "----";
		}
		cout << "*" << symbol << endl << "| ";

		if (this->size == 0)
		{
			cout << endl << "*" << symbol << endl << endl;
			return;
		}

		Node<T>** arr = new Node<T>*[this->size];
		int index = 0;

		Node<T>* temp = this->head;
		while (temp->next)
		{
			temp = temp->next;
			arr[index] = temp;
			index++;
		}

		for (int i = this->size - 1; i > -1; i--)
		{
			std::cout << arr[i]->data << "  ";
		}
		cout << endl << "*" << symbol << endl << endl;

		delete[] arr;
	}
};


int main()
{
	Stack<int> s;

	// 入栈
	s.push(10);
	s.push(20);
	s.push(30).show();

	// 出栈
	s.pop().show();
	s.pop().show();
	s.pop().show();

	system("pause");
	return 0;
}

2.队列

通过顺序表实现

在这里插入图片描述

// C++

#include<iostream>
#include<string>
using namespace std;

// 队列所存储数据的类型
typedef int E;


// 队列 (通过顺序表实现循环队列)
class Queue
{
public:
	E* arr;			// 用于记录队列的内存地址
	int capacity;	// 用于记录队列的容量
	int size;		// 用于记录队列中元素的个数
	int front;		// 用于记录队首位置
	int rear;		// 用于记录队尾位置

	Queue()
	{
		this->capacity = 5;
		this->arr = new E[this->capacity];
		this->size = 0;
		this->front = this->rear = 0;
	}

	~Queue()
	{
		delete[] this->arr;
		this->arr = nullptr;
		this->capacity = 0;
		this->size = 0;
		this->front = this->rear = 0;
	}

	// 入队
	Queue& enqueue(E data)
	{
		// 判断队列是否已满
		if (this->size == this->capacity)	return *this;

		// 循环入队
		this->arr[rear] = data;
		this->size++;
		this->rear++;
		this->rear %= this->capacity;		// 循环队列的核心算法

		return *this;
	}

	// 出队
	Queue& dequeue()
	{
		// 判断队列是否为空
		if (size == 0)	return *this;

		// 循环出队
		this->front++;
		this->size--;
		this->front %= this->capacity;		// 循环队列的核心算法

		return *this;
	}

	// 输出
	void show()
	{
		string symbol = "";
		for (int i = 0; i < this->size; i++)
		{
			symbol += "<<<<";
		}
		if (this->size == 0)	symbol = "<<<<";
		cout << symbol << endl;
		for (int i = this->front; i < this->front + this->size; i++)
		{
			cout << this->arr[i % this->capacity] << "  ";
		}
		cout << endl << symbol << endl << endl;
	}
};

int main()
{
	Queue q;	// 创建并初始化队列
	q.show();	// 输出队列里面的内容

	// 入队
	q.enqueue(10).show();
	q.enqueue(20).show();
	q.enqueue(30).show();

	// 出队
	q.dequeue().show();
	q.dequeue().show();
	q.dequeue().show();

	system("pause");
	return 0;
}

通过链表实现

在这里插入图片描述

// C++

#include<iostream>
#include<string>
using namespace std;

// 队列所存储数据的类型
typedef int E;

// 节点
class Node
{
public:
	E data;
	Node* next;

	Node()
	{
		this->next = nullptr;
	}
};

// 队列 (通过顺序表实现循环队列)
class Queue
{
public:
	Node* head;		// 头节点(队首)
	Node* tail;		// 尾节点(队尾)
	int size;		// 用于记录队列中元素的个数

	Queue()
	{
		this->head = new Node;
		this->tail = this->head;
		this->size = 0;
	}

	~Queue()
	{
		// 释放其他节点
		Node* temp = nullptr;
		while (this->head->next)
		{
			temp = this->head->next;
			this->head->next = this->head->next->next;
			delete temp;
		}

		// 释放头节点
		delete this->head;
		this->head = this->tail = nullptr;
		this->size = 0;
	}

	// 入队
	Queue& enqueue(E data)
	{
		// 创建新节点,并存入数据
		Node* newNode = new Node;
		newNode->data = data;
		newNode->next = nullptr;

		// 将新节点插入到队尾
		this->tail->next = newNode;
		this->tail = newNode;

		// 更新数据
		this->size++;

		return *this;
	}

	// 出队
	Queue& dequeue()
	{
		// 回收内存空间
		Node* temp = nullptr;
		if (this->head->next)
		{
			temp = this->head->next;
			this->head->next = this->head->next->next;
			delete temp;
		}

		// 更新数据
		this->size--;

		return *this;
	}

	// 输出
	void show()
	{
		string symbol = "";
		for (int i = 0; i < this->size; i++)
		{
			symbol += "<<<<";
		}
		if (this->size == 0)	symbol = "<<<<";
		cout << symbol << endl;
		Node* temp = this->head;
		while (temp->next)
		{
			temp = temp->next;
			cout << temp->data << "  ";
		}
		cout << endl << symbol << endl << endl;
	}
};

int main()
{
	Queue q;	// 创建并初始化队列
	q.show();	// 输出队列里面的内容

	// 入队
	q.enqueue(10).show();
	q.enqueue(20).show();
	q.enqueue(30).show();

	// 出队
	q.dequeue().show();
	q.dequeue().show();
	q.dequeue().show();

	system("pause");
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1641138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UDP编程流程(UDP客户端、服务器互发消息流程)

一、UDP编程流程 1.1、 UDP概述 UDP&#xff0c;即用户数据报协议&#xff0c;是一种面向无连接的传输层协议。相比于TCP协议&#xff0c;UDP具有以下特点&#xff1a; 速度较快&#xff1a;由于UDP不需要建立连接和进行复杂的握手过程&#xff0c;因此在传输数据时速度稍快…

【深度学习】第二门课 改善深层神经网络 Week 2 3 优化算法、超参数调试和BN及其框架

&#x1f680;Write In Front&#x1f680; &#x1f4dd;个人主页&#xff1a;令夏二十三 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;深度学习 &#x1f4ac;总结&#xff1a;希望你看完之后&#xff0c;能对…

ASV1000视频监控平台:通过SDK接入海康网络摄像机IPC

目录 一、为何要通过SDK接入海康网络摄像机 &#xff08;一&#xff09;海康网络摄像机的SDK的功能 1、视频采集和显示 2、视频存储 3、视频回放 4、报警事件处理 5、PTZ控制 6、自定义设置 7、扩展功能 &#xff08;二&#xff09;通过SDK接入的好处&#xff08;相对…

【1小时掌握速通深度学习面试3】RNN循环神经网络

目录 12.描述循环神经网络的结构及参数更新方式&#xff0c;如何使用神经网络对序列数据建模? 13.循环神经网络为什么容易出现长期依赖问题? 14.LSTM 是如何实现长短期记忆功能的? 15.在循环神经网络中如何使用 Dropout ? 16.如何用循环神经网络实现 Seg2Seq 映射? …

2024新版Java基础从入门到精通全套教程(含视频+配套资料)

前言 Java基础是所有入门java的同学必过的一关&#xff0c;基础学习的牢固与否决定了程序员未来成就的高度。因此&#xff0c;基础学习的重要性不言而喻。 但是很多同学学习java基础知识&#xff0c;要么是学的太“基础”&#xff0c;就是只会各个知识点的简单概念和使用&…

idea 新建spring maven项目、ioc和依赖注入

文章目录 一、新建Spring-Maven项目二、在Spring-context使用IOC和依赖注入 一、新建Spring-Maven项目 在pom.xml文件中添加插件管理依赖 <build><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><version>3.1</ver…

恶补《操作系统》4_2——王道学习笔记

4.1_5 文件存储空间管理 1、存储空间的划分与初始化 文件卷&#xff08;逻辑卷&#xff09;的概念目录区与文件区 2、几种管理方法 空闲表法&#xff1a;首位置长度&#xff0c;回收时注意修改空闲链表法&#xff08;空闲盘块链、空闲盘区链&#xff09;位示图法 成组链接法…

2024年 Java 面试八股文——Mybatis篇

目录 1. 什么是Mybatis&#xff1f; 2. 说说Mybatis的优缺点 3. Xml映射文件中&#xff0c;都有哪些标签 4. #{}和&{}有什么区别 5. Mybatis是如何进行分页的,分页插件的原理是什么 6. Mybatis是如何将sql执行结果封装为目标对象并返回的&#xff1f; 7. Mybatis是怎…

JavaWeb--1.Servlet

Servlet&#xff08;基础&#xff09; 1、配置依赖&#xff1a; ​ 在pom.xml文件中加入相关依赖 <dependencies><dependency><groupId>jakarta.servlet</groupId><artifactId>jakarta.servlet-api</artifactId><version>5.0.0&l…

基于Python的LSTM网络实现单特征预测回归任务(TensorFlow)

目录 一、数据集 二、任务目标 三、代码实现 1、从本地路径中读取数据文件 2、数据归一化 3、创建配置类&#xff0c;将LSTM的各个超参数声明为变量&#xff0c;便于后续使用 4、创建时间序列数据 5、划分数据集 6、定义LSTM网络 &#xff08;1&#xff09;创建顺序模…

【ESP32之旅】合宙ESP32-C3 使用PlatformIO编译和Debug调试

工程创建 首先打开PIO Home窗口&#xff0c;然后点击New Project来创建新的工程&#xff0c;工程配置选择如下图所示&#xff1a; 注&#xff1a; 选择板子型号的时候需要选择ESP32C3&#xff0c;勾选取消Location可以自定义路径。 修改配置文件 工程创建完毕之后在工程根…

模式识别作业:颜色算子的三种阈值分割算法

一、引言&#xff1a; 在图像处理中&#xff0c;我们往往需要提取图像的一些关键信息&#xff0c;比如本篇文章的内容——提取颜色&#xff0c;然而当我们需要提取某一种颜色时&#xff0c;无论图像余下的部分如何“丰富多彩”&#xff0c;他们都不再重要&#xff0c;需要被忽…

C#核心之面向对象-继承

面向对象-继承 文章目录 1、继承的基本规则1、基本概念2、基本语法3、示例4、访问修饰符的影响5、子类和父类的同名成员 2、里氏替换原则1、基本概念2、is和as3、基本实现 3、继承中的构造函数1、基本概念2、父类的无参构造函数3、通过base调用指定父类构造 4、万物之父和装箱拆…

8.k8s中网络资源service

目录 一、service资源概述 二、service资源类型 1.ClusterIP类型 2.service的nodeport类型 3.service的loadbalancer类型&#xff08;了解即可&#xff09; 4.service的externalname类型&#xff08;了解即可&#xff09; 三、nodeport的端口范围设置和svc的endpoint列表 1.修…

扩散模型(Diffusion Model)概述

扩散模型&#xff08;Diffusion Model&#xff09;是图像生成模型的一种。有别于此前 AI 领域大名鼎鼎的 GAN、VAE 等算法&#xff0c;扩散模型另辟蹊径&#xff0c;其主要思想是一种先对图像增加噪声&#xff0c;再逐步去噪的过程&#xff0c;其中如何去噪还原图像是算法的核心…

web3风格的网页怎么设计?分享几个,找找感觉。

web3风格的网站是指基于区块链技术和去中心化理念的网站设计风格。这种设计风格强调开放性、透明性和用户自治&#xff0c;体现了Web3的核心价值观。 以下是一些常见的Web3风格网站设计元素&#xff1a; 去中心化标志&#xff1a;在网站的设计中使用去中心化的标志&#xff0…

RocketMQ SpringBoot 3.0不兼容解决方案

很多小伙伴在项目升级到springBoot3.0版本以上之后&#xff0c;整合很多中间件会有很多问题&#xff0c;下面带小伙伴解决springBoot3.0版本以上对于RocketMQ 不兼容问题 报错信息 *************************** APPLICATION FAILED TO START *************************** Des…

深入 Django 模型层:数据库设计与 ORM 实践指南

title: 深入 Django 模型层&#xff1a;数据库设计与 ORM 实践指南 date: 2024/5/3 18:25:33 updated: 2024/5/3 18:25:33 categories: 后端开发 tags: Django ORM模型设计数据库关系性能优化数据安全查询操作模型继承 第一章&#xff1a;引言 Django是一个基于Python的开源…

Lucene从入门到精通

**************************************************************************************************************************************************************************** 1、概述 【1】入门&#xff1a;作用、有点与缺点 【2】应用&#xff1a;索引、搜索、fie…

最短路径(朴素)+堆排序+模拟堆

文章目录 Dijkstra求最短路 I堆排序模拟堆 Dijkstra求最短路 I 给定一个 n 个点 m 条边的有向图&#xff0c;图中可能存在重边和自环&#xff0c;所有边权均为正值。 请你求出 1 号点到 n 号点的最短距离&#xff0c;如果无法从 1 号点走到 n 号点&#xff0c;则输出 −1。 输…