单链表算法题目学习
一、题目介绍
实现一个双链表,双链表初始为空,支持 5 种操作:
在最左侧插入一个数;
在最右侧插入一个数;
将第 k 个插入的数删除;
在第 k 个插入的数左侧插入一个数;
在第 k 个插入的数右侧插入一个数
现在要对该链表进行 M 次操作,进行完所有操作后,从左到右输出整个链表。
注意:题目中第 k 个插入的数并不是指当前链表的第 k 个数。例如操作过程中一共插入了 n 个数,则按照插入的时间顺序,这 n 个数依次为:第 1 个插入的数,第 2 个插入的数,…第 n 个插入的数。
输入格式
第一行包含整数 M,表示操作次数。
接下来 M 行,每行包含一个操作命令,操作命令可能为以下几种:
L x,表示在链表的最左端插入数 x。
R x,表示在链表的最右端插入数 x。
D k,表示将第 k 个插入的数删除。
IL k x,表示在第 k 个插入的数左侧插入一个数。
IR k x,表示在第 k 个插入的数右侧插入一个数。
输出格式
共一行,将整个链表从左到右输出。
数据范围
1≤M≤100000
所有操作保证合法。
输入样例:
10
R 7
D 1
L 3
IL 2 10
D 3
IL 2 7
L 8
R 9
IL 4 7
IR 2 2
输出样例:
8 7 7 3 2 9
二、分析题目
代码如下(示例):
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100000+10;
//head表示头节点的下标
//e[i]表示节点对应的val值
//ne[i]表示节点i的next指针是多少
//idx表示存储当前已经用到哪一个点
int head,e[N],ne[N],idx;
//对链表进行初始化
void init(){
head = -1;//最开始的时候,链表的头节点要指向-1,
//为的就是在后面进行不断操作后仍然可以知道链表是在什么时候结束
/*
插句题外话,我个人认为head其实就是一个指针,是一个特殊的指针罢了。
刚开始的时候它负责指向空结点,在链表里有元素的时候,它变成了一个指向第一个元素的指针
当它在初始化的时候指向-1,来表示链表离没有内容。
*/
idx = 0;
//idx在我看来扮演两个角色,第一个是在一开始的时候,
//作为链表的下标,让我们好找
//第二在链表进行各种插入,删除等操作的时候,
//作为一个临时的辅助性的所要操作的元素的下
//标来帮助操作。并且是在每一次插入操作的时候,
//给插入元素一个下标,给他一个窝,感动!
/*
再次插句话,虽然我们在进行各种操作的时候,
元素所在的下标看上去很乱,但是当我们访问的
时候,是靠着指针,也就是靠ne[]来访问的,
这样下标乱,也就我们要做的事不相关了。
另外,我们遍历链表的时候也是这样,靠的是ne[]
*/
}
//加一个节点
void add_list_head(int x){//和链表中间插入的区别就在于它有head头节点
e[idx] = x;//第一步,先将值放进去
ne[idx] = head;//head作为一个指针指向空节点,现在ne[idx] = head;
//做这把交椅的人换了
//先在只是做到了第一步,将元素x的指针指向了head原本指向的
head = idx;//head现在表示指向第一个元素了,它不在是空指针了。(不指向空气了)
idx ++;//指针向下移一位,为下一次插入元素做准备。
}
// 将下标是k的点后面的点删掉
void remove(int k){
ne[k]=ne[ne[k]];//让k的指针指向,k下一个人的下一个人,那中间的那位就被挤掉了。
}
// 在第 k 个插入的数后插入一个点
void add_list_k(int k,int x){
e[idx] = x;//先将元素插进去
ne[idx] = ne[k];//让元素x配套的指针,指向它要占位的元素的下一个位置
ne[k] = idx;//让原来元素的指针指向自己
idx ++;//将idx向后挪
/*
为了将这个过程更好的理解,现在
将指针转变的这个过程用比喻描述一下,牛顿老师为了省事,想插个队,队里有两个熟人
张三和李四,所以,他想插到两个人中间,但是三个人平时关系太好了,只要在一起,就
要让后面的人的手插到前面的人的屁兜里。如果前面的人屁兜里没有基佬的手,将浑身不
适。所以,必须保证前面的人屁兜里有一只手。(张三在前,李四在后)
这个时候,牛顿大步向前,将自己的手轻轻的放入张三的屁兜里,(这是第一步)
然后,将李四放在张三屁兜里的手抽出来放到自己屁兜里。(这是第二步)
经过这一顿骚操作,三个人都同时感觉到了来自灵魂的战栗,打了个哆嗦。
*/
}
int main()
{
int n,k,x;
cin>>n;
init();
while (n -- ){
char s;
cin>>s;
if (s == 'H'){
cin>>x;
add_list_head(x);
}else if (s == 'D'){
cin>>k;
if (k == 0) head = ne[head];//删除头节点
else remove(k - 1);//注意删除第k个输入后面的数,那函数里放的是下标,k要减去1
}else if (s == 'I'){
cin>>k>>x;
add_list_k(k-1,x);//同样的,第k个数,和下标不同,所以要减1
}
}
for(int i=head ;i!=-1;i=ne[i])cout<<e[i]<<' ';//遍历整个链表输出链表
cout<<endl;
return 0;
}
总结单链表算法思路
看上面注释就明白了