当前位置:   article > 正文

算法比赛必备-数组模拟链表

数组模拟链表

为什么要用数组模拟

众所周知,链表是通过指针将所有的结点相连接,以此来达到快速插入和删除的数据结构。但是在

很多时候,特别是在学校、书本里面,大多都是用的结构体,而使用结构体的劣势也显而易见:前戏长,运算慢。在我们平时做算法题还是练习的时候,我们推荐使用数组模拟。

当然,队列、栈、二叉树 这些也可以用数组模拟。

结构体实现链表

  1. // 定义结构体
  2. typedef struct LNode {
  3. ElemType data;
  4. struct LNode *next;
  5. }LNode, *LinkList;
  6. // 在单链表中取得第i个元素
  7. Status getElem L(LinkList L,int i,ElemType &e) {
  8. // L为带头结点的单链表指针。
  9. // 当第i个元素存在时,其赋给e并返回,否则返回Error
  10. p = L->next, j=1; // 初始化,p指向第一个结点,j为计数器。
  11. while(p && j<i) { // 从头结点开始查找,知道p指向第i个结点或 p 为空
  12. p = p->next ;
  13. ++j;
  14. }
  15. if(!p ||j>i) return ERROR; // 第i个元素不存在
  16. e = p-> data; // 取第i个元素并返回
  17. return e;
  18. }
  19. // 在单链表中第i个位置之前插入元素e
  20. Status ListInsert L(LinkList &L,int i, ElemType e) { // & 返回哪个参数
  21. p = L , j=0;
  22. while(p && j < i-1) { // 寻找第i-1个结点
  23. p = p-> next;
  24. ++j;
  25. }
  26. if(!p || j>i-1) return ERROR; // i小于1 或者 i大于表长+1(健壮性处理)
  27. s = (LinkList)malloc (sizeof LNode);
  28. s->data = e;
  29. s->next = p->next;
  30. p -> next = s;
  31. // 指针操作,注意前后顺序
  32. }
  33. // 在单链表中删除第i个元素 并返回删除的值为e
  34. Status ListDelete L(LinkList &L,int i,ElemType &e) {
  35. p = L,j=0; // 初始化
  36. while(p->next && j<i-1){
  37. p = p->next ;
  38. ++j;
  39. }
  40. if(!(p->next) || j>i-1) return ERROR;
  41. q = p->next ;
  42. p->next = q->next; // 删除并释放结点(q)
  43. e = q->data;
  44. free(q);
  45. // 注意操作顺序
  46. }

数组实现单链表

定义变量: idx,head , h[ ], ne[ ] , e[ ] 。

idx:链表的下标。 在进行删除,插入操作时作为辅助元素帮助操作。

head:链表头结点。

ne[]:指向当前元素位置的下一个位置。

e[]:保存当前节点的值。

定义基本方法:init_list() 、 insert_head() 、add() 、 remove() 。

  1. // 对链表进行初始化。
  2. void init_list(){
  3. idx = 0; // 令当前下标0 (c++全局变量初试为0)
  4. head = -1; // 链表的头节点要指向-1
  5. }
  6. //将x插入到头节点上
  7. void insert_head(int x) {
  8. e[idx] = x; //第一步,先将值放进去
  9. ne[idx] = head; //head作为一个指针指向上一个头结点,现在ne[idx] = head 相当于 新添加的元素
  10. // 指向上一个更新的头结点。
  11. head = idx; //更新head结点进行迭代。
  12. idx ++; //指针向下移一位。
  13. }
  14. //将x插入到下标为k的点的后面
  15. void add(int k, int x){
  16. e[idx] = x;//先将元素插进去
  17. ne[idx] = ne[k];//让元素x配套的指针,指向它要占位的元素的下一个位置
  18. ne[k] = idx;//让原来元素的指针指向自己
  19. idx ++;//将idx向后挪
  20. }
  21. //将下标是k的结点后面的点删除
  22. void remove(int k){
  23. ne[k] = ne[ne[k]]; //让k的指针指向k下一个结点的下一个结点 。
  24. }

 值得注意的是 ,在数组模拟链表这几个基本方法中,需尤为注意操作的顺序。例如:在 add() 方法中,如果把

ne[idx] = ne[k] 和  ne[k] = idx  互换位置 ,那结果就不一样了, 因为在其之前, ne[k] 的位置已经不一样了 ,这个时候再去指向 ne[k] 就错了。

例题示范

 借鉴 Acwing 里面一道模板题 

826. 单链表 - AcWing题库

 思路:定义好基本变量后 ,使用数组模拟链表或者使用c++自带的STL(之前在洛谷看到过一句话,很深刻:我们通过努力去尝试AC的每一道题,不是目标,而是训练。所以说学习这种东西真的是多多益善 0.0) 。然后写好各自方法体。

AC代码: 

  1. #include <iostream>
  2. #include <algorithm>
  3. using namespace std;
  4. const int N = 100010;
  5. int head, e[N],h[N],ne[N], idx;
  6. int n;
  7. void init(){
  8. head = -1;
  9. idx = 0;
  10. }
  11. // 头结点插值
  12. void inset_head(int x){
  13. e[idx] = x;
  14. ne[idx] = head;
  15. head = idx;
  16. idx ++ ;
  17. }
  18. // 将x插入到下标是k的结点的后面
  19. void add(int k, int x){
  20. e[idx] = x;
  21. ne[idx] = ne[k];
  22. ne[k] = idx;
  23. idx ++ ;
  24. }
  25. // 将k点后面的点删除
  26. void remove(int k){
  27. ne[k] = ne[ne[k]];
  28. }
  29. int main(){
  30. cin >> n;
  31. init();
  32. while (n--){
  33. int k, x;
  34. char op;
  35. cin >> op;
  36. if (op == 'H'){
  37. cin >> x;
  38. inset_head(x);
  39. }
  40. else if (op == 'D'){
  41. cin >> k;
  42. if (!k) head = ne[head];
  43. remove(k - 1);
  44. }
  45. else{
  46. cin >> k >> x;
  47. add(k - 1, x);
  48. }
  49. }
  50. for (int i = head; i != -1; i = ne[i]) cout << e[i] <<" ";
  51. return 0;
  52. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/556371
推荐阅读
相关标签
  

闽ICP备14008679号