题目来源:P1160 队列安排 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
1.对于这题我们用暴力解法,也就正常的对数据插入删除,时间复杂度肯定不言而喻,所以我们需要对自己的代码稍加改进。
我们知道对于链表,我们查找非常耗时,特别对于一个很长的数据,要找到后面的数据,那是非常耗时,但找到数据之后,链表的删除操作速度就非常快了。而对于顺序表,也就是我们常谈的数组,我们可以直接通过下标找到一个数。
有什么方法可以结合这两种存储结构的特点呢?
我们可以考虑使用数组存取每一个节点吗?
那肯定是不行的,但我们可以用数组存储这个指针的地址,通过访问数组快速的找到这个节点。
这样就结合了顺序表和链表的特性,减少了算法的时间复杂度。
如下:用数组存储了在链表上的节点,数组的下标就是对应的要找的节点的值。
如图,我们可以通过一个结构体数组指针来快速的找到各个节点,在利用链表快速插入、删除。
2.首先我们定义一个结构体,我们可以用一个结构体指针数组存放每个节点的指针,数组的下标就是对应的同学编号,数组的值对应指向该同学编号的指针,这样不仅查找时间为O(1),删除和插入也为O(1)。
#include
using namespace std;
typedef struct Node
{
int val;
Node *next;
} Node, *linkedList;
插入函数的传入的第一个参数为当前要插入的编号为k的同学在链表上的位置,x为要插入的同学的编号,返回的是指向要插入节点的指针(不难发现,这个插入只能插在当前节点的后面)所以我们应再写一个插入函数。
四.写前插的插入函数(p==0):
因为我们能通过list1[k]快速找到k节点指针,但却没有k节点前的指针,却可以通过k节点访问x后的节点,所以我们可以考虑先将x节点插入到k节点的后面然后再交换k节点和x节点的值,这样就做了前插。
五.定义一个ma[100005]数组并初始化值全为0和写一个删除函数。
数组ma[100005]的用意是记录删除,也就是防止重复删除。
int ma[100005] = {0};
第一步:初始化变量:
int n, m, ma[100005] = {0}, k, p, x; linkedList list = new Node; list->next = NULL; linkedList *list1; list1 = new linkedList[100005];//初始化结构体指针数组 list1[1] = insert(list, 1);//将第一个同学插入
第二步:写n-1次的插入循环
cin >> n;
for (int i = 2; i <= n; i++)
{
cin >> k >> p;
if (p == 1)
{
list1[i] = insert(list1[k], i);
}
else
{
list1[i] = push(list1[k], i);
list1[k] = list1[i]->next; //因为采用的是特殊的前插,所以指针也要修改
}
}
第三步:写m次的删除循环 (注意避免重复删除)
cin >> m;
for (int i = 1; i <= m; i++)
{
cin >> x;
if (ma[x] == 1)
continue; //如果已删除,则跳过本次操作
ma[x] = 1;
remove(list1[x]);
}
第四步:打印结果:
Node *L = list->next;
while (L)
{
cout << L->val << " ";
L = L->next;
}
七、提交结果
八、全代码
#include
using namespace std;
typedef struct Node
{
int val;
Node *next;
} Node,*linkedList;
//后插
linkedList insert(Node *list, int x)
{
Node *p = new Node;
p->val = x;
p->next = list->next;
list->next = p;
return p;
}
//前插 -->(先后插再换值,相当于后插,多了一步换值)
linkedList push(Node *list, int x)
{
Node *p = new Node;
p->val = list->val;
list->val = x;
p->next = list->next;
list->next = p;
return list;
}
//删除
void remove(Node *list)
{
Node *p = list->next;
list->val = p->val;
list->next = p->next;
delete p;
}
int main()
{
int n, m, ma[100005] = {0}, k, p, x;
linkedList list = new Node;
list->next = NULL;
linkedList *list1;
list1 = new linkedList[100005];
list1[1] = insert(list, 1);
cin >> n;
for (int i = 2; i <= n; i++)
{
cin >> k >> p;
if (p == 1) //前插
{
list1[i] = insert(list1[k], i);
}
else //后插
{
list1[i] = push(list1[k], i);
list1[k] = list1[i]->next;
}
}
//删除
cin >> m;
for (int i = 1; i <= m; i++)
{
cin >> x;
if (ma[x] == 1) //避免重复删除
continue;
ma[x] = 1;
remove(list1[x]);
}
//打印结果
Node *L = list->next;
while (L)
{
cout << L->val << " ";
L = L->next;
}
return 0;
}
如果你的思路和我的一样却有错误,可以考虑是不是在前插操作时忘记该结构体数组指针了;