一、单链表
1、单链表
输入样例:
10
H 9
I 1 1
D 1
D 0
H 6
I 3 6
I 4 5
I 4 5
I 3 4
D 6
输出样例:
6 4 6 5
实现方式1:结构体+链表(很慢,因此暂时不用)
struct Node
{
int val;
Node *next;
}
new Node();//非常慢
实现方式2:数组模拟链表:
静态数组模拟链表比动态指针链表速度要快
单链表中用的最多的是邻接表(邻接表,实际就是n个链表)
邻接表的用途:存储树和图
双链表的作用:优化某些问题
定义:
//head表示: 头结点的下标
//e[i]表示: 结点i的值
//ne[i]表示:结点i的next指针是多少,即结点i的下一个值的下标
//idx: 存储当前用到了哪个点,相当于指针
int head,e[N],ne[N],idx;
初始化:
void init()
{
head=-1; //表示空集
idx=0; //点从0开始分配
}
插入操作:
时间复杂度:O(1)
插入操作1:将一个数 x 插入到头结点后面
//第一步:将指针指向head的下一个位置
//第二步:将head原本指向(head下一位)的指针删掉,改为(head指向 x)
//idx存的是:当前可以用的最新点的下标
void add_to_head(int x)
{
e[idx]=x; //将x的值存起来
//链表原本为空,于是head指向空结点,
//但是现在 在head后插入一个数,head就不指向空结点了,改为idx指向空结点,
//就将head赋值给ne[idx]
ne[idx]=head;
head=idx; //head现在指向第一个元素,不过由于head是下标,因此将idx赋值给head
idx++;
}
插入操作2:将一个数x插入到(下标为k的点)后面
//和上面在头结点后面插入数用法类似,将head换成ne[k]
void add(int k,int x)
{
e[idx]=x;
ne[idx]=ne[k];
ne[k]=idx;
idx++:
}
删除操作:
将(下标为k的点)的后面一个点 删掉
void remove(int k)
{
//跳过一个数,则指针ne也要跳过一个
//ne[ne[k]]表示:指向(当前指向ne[k])的下一个指向
ne[k]=ne[ne[k]];
}
AC代码:
#include<iostream>
using namespace std;
const int N=100010;
//定义
int head,e[N],ne[N],idx;
//初始化
void init()
{
head=-1;
idx=0;
}
//操作1:将x插入到头结点
void add_to_head(int x)
{
e[idx]=x,ne[idx]=head,head=idx,idx++;
}
//操作2:删除第k个插入的数后面的数
//因为idx初始化为0,每次插入一个新的数后,idx+1
//所以 第一个插入的点的下标为0,第k个插入的点的下标为k-1
//因此:第k个删掉点,就是下标为 k-1的点
void remove(int k)
{
ne[k]=ne[ne[k]];
}
//操作3:在第k个插入的数后面插入一个数
//即:将x插入到下标是k的点后面
void add(int k,int x)
{
e[idx]=x,ne[idx]=ne[k],ne[k]=idx,idx++;
}
int main()
{
int m;
cin>>m;
init();//一定不要忘记初始胡!!!
while(m--)
{
int k,x;
char s;
cin>>s;
if(s=='H')//操作1
{
cin>>x;
add_to_head(x);
}
if(s=='D')//操作2
{
cin>>k;
if(k==0)//当k为0时,删除掉头结点
head=ne[head];
else
remove(k-1);//第k个数,它的下标为k-1
}
if(s=='I')//操作3
{
cin>>k>>x;
add(k-1,x);//同样的,第k个数,它的下标为k-1
}
}
//遍历输出,注意i从head开始遍历,而不是从idx,这里是没有idx的
for(int i=head; i!=-1; i=ne[i])
cout<<e[i]<<' ';
cout<<endl;
return 0;
}