数组模拟链表

  • Post author:
  • Post category:其他




链表


为什么使用数组来模拟链表


如果数据规模很大, 一个一个的new操作太慢了, 会超时, 使用数组会大大加快速度



单链表

数组模拟单链表

**idx = 0开始的, 所以第k个元素的下标就是 k-1 传值的时候要注意 **

image-20220109111634462

数组表示单链表.png



例题

例题 :

单链表

实现一个单链表,链表初始为空,支持三种操作:

向链表头插入一个数;

删除第 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

所有操作保证合法。



输入样例:

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



java代码

import java.io.*;
import java.util.Scanner;

public class Main {
    private static int N = 100010;  // 数据规模为 10w

    private static int head;                // 表示头结点的下标
    private static int[] e = new int[N];    // 表示结点 i的值
    private static int[] ne = new int[N];   // 表示结点 i的 next指针是多少
    private static int idx;                 // 表示存储当前结点已经使用结点的下一个结点

    // 初始化数据
    private static void init() {
        head = -1;  // 没有头结点
        idx = 0;    // 没有存入数据
    }

    // 将 val插到头结点
    private static void addToHead(int val) {
        e[idx] = val;   // 赋值
        ne[idx] = head; // 插入之前头结点的前面
        head = idx;     // 更新头结点信息
        idx++;          // idx向右移动
    }

    // 将下标是 k的点后面的点删掉
    private static void remove(int k) {
        ne[k] = ne[ne[k]];  // 让下标为 k的结点指向 下个结点的下个结点
    }

    // 将 val插入下标为 k的点的后面
    private static void add(int k, int val) {
        e[idx] = val;
        ne[idx] = ne[k];
        ne[k] = idx;
        idx++;
    }

    // 程序入口
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        int m = Integer.parseInt(reader.readLine());

        init();     // 初始化操作

        // 进行 m次操作
        while (m-- > 0) {
            String[] s = reader.readLine().split(" ");

            if (s[0].equals("H")) {  // 插入头结点操作, 不能使用 ==, 要使用 equals()

                int val = Integer.parseInt(s[1]);
                addToHead(val);
            } else if (s[0].equals("I")) {   // 普通插入操作
                int k = Integer.parseInt(s[1]);
                int val = Integer.parseInt(s[2]);
                add(k - 1, val);    // 第 k个结点的下标为 k-1, 所以插入到下标为 k-1结点的后面
            } else {    // s[0] == "D", 删除操作
                int k = Integer.parseInt(s[1]);

                if (k == 0) {  // 题意: k = 0, 删除头结点
                    head = ne[head];
                } else
                    remove(k - 1);  // 第 k个结点的下标为 k-1, 所以是删除到下标为 k-1后面的后面
            }
        }

        // 打印输出
        for (int i = head; i != -1; i = ne[i]) {
            System.out.print(e[i] + " ");
        }
    }
}



双链表

实现双链表的基本操作 :

  1. 首先是结构 以及初始化操作

    image-20220109123445177

    为什么没有头呢 ?


    这里使用下标为 0 作为头结点 下标为 1 作为尾结点

    所以初始化的时候就要注意了 先将 0 和 1 连接起来

    image-20220109123651947

  2. 插入删除操作

插入的话 其实不分最左还是左右 以及在k的左还是右插入 统统一个方法即可 实现在k的右边插入

最左插入的话就是在不断的在0的右边插入

最右插入的话就是在不断的在1的左边的值的右边插入

删除的话就好说了

!!!**还有就是因为 idx是从 2 开始的 所以第k个元素的下标就是 k+1 **

//IL  IR  第k个数右插入
    public static void insert(int k , int x){
        e[idx] = x;
        re[idx] = re[k];
        le[idx] = k;
        le[re[k]] = idx;  //先
        re[k] = idx;      //后
        idx++;
    }
    //del 删除第k个数
    public static void del(int k ){
        re[le[k]] = re[k]; 
        le[re[k]] = le[k]; 
    }
  1. 遍历输出 注意遍历输出的for写法

    for(int i= re[0];i!=1;i = re[i]){
        System.out.print(e[i]+" ");
    }
    


例题

双链表

实现一个双链表,双链表初始为空,支持 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




java代码

import java.util.*;

public class Main{
    
    static int[] e = new int[100010];  //存放具体的值
    static int[] le = new int [100010 ]; //左值的下标
    static int[] re = new int [100010 ]; //左值的下标
    static int idx = 0;   //当前操作的索引
    
    //初始化
    public static void init(){
        //这里的话  直接使用0号点做为head   使用=1号点做为tail  
        //给0 1 初始化
        re[0] = 1;
        le[1] = 0;
        idx = 2;  //0 1 被占用了所以从2号点开始
    }
    
    //IL  IR  第k个数右插入
    public static void insert(int k , int x){
        e[idx] = x;
        re[idx] = re[k];
        le[idx] = k;
        le[re[k]] = idx;  //先
        re[k] = idx;      //后
        idx++;
    }
    //del 删除第k个数
    public static void del(int k ){
        re[le[k]] = re[k]; 
        le[re[k]] = le[k]; 
    }
    
    public static void main(String[] args){
        
        init();  //切记要初始化嗷嗷  !!!!!
        
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        while(n-- >=0){
            String s = sc.nextLine();
            //System.out.println(s);
            String[] s1 = s.split(" ");
            if(s1[0].equals("R")){
                //执行最右插入  k就是1的左边
                 int k = le[1];
                int x = Integer.parseInt(s1[1]);
                insert(k,x);
            }
            if(s1[0].equals("L")){
                //执行最左插入  就是0的右边
                int k = 0;
                int x = Integer.parseInt(s1[1]);
                insert(k,x);
            }
            if(s1[0].equals("D")){
                //执行删除
              del(Integer.parseInt(s1[1])+1);
                
            }
            if(s1[0].equals("IL")){
             
                int k = Integer.parseInt(s1[1]);
                int x = Integer.parseInt(s1[2]);
                
                insert(le[k+1],x);
            }
            if(s1[0].equals("IR")){
                 int k = Integer.parseInt(s1[1]);
                int x = Integer.parseInt(s1[2]);
                 insert(k+1,x);
            }
        }
        
        for(int i= re[0];i!=1;i = re[i]){
            System.out.print(e[i]+" ");
        }
        
        
    }
}



版权声明:本文为qq_45834768原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。