用数组模拟链表
1.单链表
-
head模拟头结点;
-
e[ ]存数值,模拟data;
-
ne[ ]存下一个结点的下标,模拟next;
-
结束用-1表示,模拟NULL。
Subject: 实现一个单链表,链表初始为空,支持三种操作: 向链表头插入一个数; 删除第 k 个插入的数后面的数; 在第 k 个插入的数后插入一个数。 现在要对该链表进行 M 次操作,进行完所有操作后,从头到尾输出整个链表。 注意:题目中第 k 个插入的数并不是指当前链表的第 k 个数。例如操作过程中一共插入了 n 个数,则按照插入的时间顺序,这 n 个数依次为:第 1 个插入的数,第 2 个插入的数,…第 n 个插入的数。 输入格式 第一行包含整数 M,表示操作次数。 接下来 M 行,每行包含一个操作命令,操作命令可能为以下几种: H x,表示向链表头插入一个数 x。 D k,表示删除第 k 个插入的数后面的数(当 k 为 0 时,表示删除头结点)。 I k x,表示在第 k 个插入的数后面插入一个数 x(此操作中 k 均大于 0)。 输出格式 共一行,将整个链表从头到尾输出。 数据范围 1≤M≤100000 所有操作保证合法。
#include<stdio.h> //e[i]存结点i的数据 //ne[i]存结点i的next指针 //head存头结点的指针域 //idx是当前最新的结点数,即已经用到哪个点了 //-1代表空结点 int e[100009], ne[100009], head, idx; //初始化 void init() { head = -1;//链表最开始指向NULL idx = 0;//数组下标从0开始 } //把x插入到头结点 void insert_head(int x) { e[idx] = x;//把x存入 ne[idx] = head;//把原头结点所在位置给新的,即连接新头结点和旧头结点 head = idx;//更新头指针地址 idx++;//指向下一位 } //把x插入到k位后,变成a x a+1 void insert(int x, int k) { e[idx] = x; ne[idx] = ne[k];//连接x和a+1 ne[k] = idx;//连接a和x idx++; } //删除第k个后的数 void remove(int k) { ne[k] = ne[ne[k]];//ne[k]是第k个后的数,即要删除的数;ne[ne[k]]要删除数后的数 //即实现链表跨越第k个数 } int main() { int m,k,x; init(); scanf("%d", &m); while (m--) { getchar(); char c; scanf("%c", &c); if (c == 'H') { scanf("%d", &x); insert_head(x); } else if (c == 'I') { scanf("%d%d", &k, &x); insert(x,k-1);//数组从0开始 } else { scanf("%d", &k); if (k == 0)//删除头结点 { head = ne[head];//head直接后移 } else { remove(k - 1);//∵数组从0开始,所以要-1 } } } for (int i = head; i != -1; i = ne[i])//从head开始,依次找下一个数据下标 { printf("%d ", e[i]); } return 0; }
2.双链表
Subject: 实现一个双链表,双链表初始为空,支持 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 所有操作保证合法。
-
初始化
-
把下标为idx,值为x的新结点插入到k的右端
-
删除下标为k的点
#include<stdio.h> #include<stdlib.h> #include<string.h> int m; int r[100009], l[100009], e[100009],idx; //r[i]存第i个右边的数的下标 //l[i]存第i个左边的数的下标 //e[i]存第i个数的值 //ixd存当前最新的数,即最新下标 //初始化 void init() { idx = 2;//初始时有两个元素 r[0] = 1;//第一个元素的右端点为1 l[1] = 0;//第二个元素的左端点为0 } //在k右边插入数 x void insert(int k, int x) { e[idx] = x; r[idx] = r[k]; l[idx] = k; l[r[k]] = idx; r[k] = idx; idx++; } //删除第k位的数 void del(int k) { r[l[k]] = r[k]; l[r[k]] = l[k]; } //输出 void output() { for (int i = r[0]; i != 1; i = r[i]) { printf("%d ", e[i]); } } int main() { int m,x,k; scanf("%d", &m); init(); while (m--) { getchar(); char c[3]; scanf("%s", c); if (strcmp(c,"L")==0) { scanf("%d", &x); insert(0, x); } else if (strcmp(c,"R")==0) { scanf("%d", &x); insert(l[1], x);//l[1]代表尾结点左边的数,即最后一个数 } else if (strcmp(c,"D")==0) { scanf("%d", &k); del(k+1);//因为初始化时加了两个结点 数组又从0开始算∴k+2-1 } else if (strcmp(c, "IL")==0) { scanf("%d%d",&k,&x); insert(l[k+1], x);//在第k个插入的数 左结点后插入x } else { scanf("%d%d", &k, &x); insert(k+1, x);//在k结点后插入 } } output(); return 0; }
3.栈
-
栈:先进先出
-
队列:先进后出
Subject: 实现一个栈,栈初始为空,支持四种操作: push x – 向栈顶插入一个数 x; pop – 从栈顶弹出一个数; empty – 判断栈是否为空; query – 查询栈顶元素。 现在要对栈进行 M 个操作,其中的每个操作 3 和操作 4 都要输出相应的结果。 输入格式 第一行包含整数 M,表示操作次数。 接下来 M 行,每行包含一个操作命令,操作命令为 push x,pop,empty,query 中的一种。 输出格式 对于每个 empty 和 query 操作都要输出一个查询结果,每个结果占一行。 其中,empty 操作的查询结果为 YES 或 NO,query 操作的查询结果为一个整数,表示栈顶元素的值。 数据范围 1≤M≤100000, 1≤x≤109 所有操作保证合法。
#include<stdio.h> #include<string.h> int a[100009], k = 0; void pu(int x) { a[k] = x; k++; } void po() { k--; } void em() { if (k > 0) { printf("NO\n"); } else { printf("YES\n"); } } void qu() { printf("%d\n", a[k-1]); } int main() { int m,x; scanf("%d", &m); while (m--) { getchar(); char s[9]; scanf("%s", s); if (strcmp(s, "push") == 0) { scanf("%d", &x); pu(x); } else if (strcmp(s, "pop") == 0) { po(); } else if (strcmp(s, "empty") == 0) { em(); } else { qu(); } } return 0; }