这是一个学习笔记,笔者在学习了数据结构的单链与acwing的课程后所写。
为什么使用数组来模拟链表
一般面试会采用如下方法。
struct Node
{
int data;
Node* next;
};
但是,我们每一次创建一个新的链表的时候会调用一次new函数
new Node();
该操作非常慢,在面对大量的数据时会非常的耗时间,所以我们采用数组的形式来模拟。
单链表的原理
使用两个数组。一个数组(Data[N])来存储数据,等价于数据结构的数据域;另一个数据(Next[N])来存储该点下一个数据的下标,等价于数据结构的指针域。
准备工作
/*
head表示头结点的下标
Data[i]表示节点i的元素值
Next[i]表示节点i的Next指针是多少
idx储存当前用到了哪一个点
*/
#define N 10
int head, Data[N], Next[N], idx;
初始化
void init()
{
head = -1;//此时链表为空,所以头节点指向空集
idx = 0;//此时链表为空,所以用到了第0个点
}
插入操作
插入操作有一以下三种,头插 尾插 按位插入
头插操作
// 将x插入到链表的头部
void add_to_head(int x)
{
if (idx >= N)//增加判断操作,以提高代码的健壮性
{
cout << "错误: add_too_head 中数组溢出" << endl;
return;
}
Data[idx] = x;//第一步
Next[idx] = head;//第二步
head = idx;//第三步
idx++;
}
尾插操作
// 将x插入到链表的尾部
void add_to_tail(int x)
{
if (idx >= N)
{
cout << "错误: add_too_tail 中数组溢出" << endl;
return;
}
Data[idx] = x;
Next[idx] = -1;
if (head == -1)//增加判断,检查链表是否为空,并在链表为空的情况下,将新节点设置为链表的第一个节点
{
head = idx;//说白了,就是头插操作
}
else
{
int i = head;
while (Next[i] != -1)// 遍历链表,找到最后一个节点
{
i = Next[i];
}
Next[i] = idx;// 将新节点插入到链表的末尾
}
idx++;
}
不画图啦,和头插操作类似。
按位插入
在第k个结点后添加某个数据元素。
// 在第k个节点后插入x
void add_to_kth(int k, int x)
{
if (k < 0 || k >= idx)//防止
{
cout << "错误: add 中的索引无效" << endl;
return;
}
if (idx >= N)
{
cout << "错误: add 中数组溢出" << endl;
return;
}
//储存
Data[idx] = x;//第一步
//将新节点的Next指针指向原第k个节点的Next指针所指向的节点
Next[idx] = Next[k];//第二步
//将第k个节点的Next指针指向新节点
Next[k] = idx;//第三步
idx++;
}
按位删除
// 删除第k个节点
void remove(int k)
{
if (k < 0 || k >= idx)// 检查k是否正确
{
cout << "错误: remove 中的索引无效" << endl;
return;
}
if (Next[k] == -1)// 检查要删除的节点是否有下一个元素
{
cout << "错误: 无法删除无下一元素的节点" << endl;
return;
}
Next[k] = Next[Next[k]];// 将第k个节点的Next指针指向其下一个节点的下一个节点
//一般在做题的过程中,我们不考虑内存的问题,链表中没有出现该元素,即为已删除
}
测试环节
在测试中添加了如下代码用于打印链表
void print_list()
{
int i = head;
while (i != -1)
{
cout << Data[i] << " ";
i = Next[i];
}
cout << endl;
}
测试代码
init(); // 初始化链表
// 测试插入操作
add_to_head(1); // 插入到头部
add_to_tail(2); // 插入到尾部
add_to_kth(0, 3); // 在第0个节点后插入3
add_to_kth(1, 4); // 在第1个节点后插入4
// 打印链表
cout << "链表内容: ";
print_list();
// 测试删除操作
remove(1); // 删除第1个节点
// 打印链表
cout << "删除第1个节点后的链表内容: ";
print_list();