hash + 双向链表O(1)插入和查找。java和C++版

  • 使用顺序表记录链表的地址,从而实现O(1)的hash查找
  • 使用双向链表进行O(1)的插入

双向链表需要注意的点:

  1. 插入第一个结点的时候需要判断空
  2. 前插的时候,需要看是否插入第一个
    a. 如果是,不用指向自己
    b. 如果不是,头结点需要更新
  3. 向后插的时候,需要看是否插入最后一个,如果是,不用更新后一个的前结点。
//STl自行车停放
#include<bits/stdc++.h>
using namespace std;
long long n,x,a,b,c;
list<int> :: iterator loc[100003];
int main(){
    long long i; // 内存地址,使用long long 防止爆int
    list<int> L;
    cin>>n>>x;
    L.push_back(x); //把x插入
    loc[x] = L.begin(); //x的地址为链表的起始值
    list<int> :: iterator temp;
    for(int i=1;i<=n-1;i++){
        cin>>a>>b>>c; //a为代插元素,b为已有元素,c为方向
        temp = loc[b]; //b的地址给temp
        if(c==0){//左边插入
            L.insert(temp,a);
            loc[a] = --temp;
        }
        else{
            //右边插入
            L.insert(++temp,a);
            loc[a] =--temp;
        }
    }
for(list<int>::iterator it = L.begin() ; it!=L.end() ; it++)
cout << *it <<" ";
}
  • java实现
package lanqiao.imporve;

import java.io.*;
import java.lang.reflect.Array;
import java.util.*;

/**
 * @author: Zekun Fu
 * @date: 2022/12/19 23:45
 * @Description:
 */
public class ZiXingChe {
    /**
     * 双向链表的实现
     *
     * @author liyanan
     * @date 2020/1/2 13:16
     */
    public static class SNode<T> {
        /**
         * 存储数据
         */
        public T data;
        /**
         * 指向当前结点的前一个结点
         */
        public SNode<T> pre;
        /**
         * 指向当前结点的下一个节点
         */
        public SNode<T> next;

        public SNode() {
        }

        public SNode(T data) {
            this.data = data;
        }
    }

    public static class DoubleLinkedList<T> {

        /**
         * 双向链表的头结点,存储第一个有效结点的基地址
         */
        private SNode<T> head;

        /**
         * 双向链表的有效结点数量
         */
        private int size;

        public DoubleLinkedList() {
            head = null;
            size = 0;
        }

        public int getSize() {
            return size;
        }


        public boolean isEmpty() {
            return size == 0;
        }

        /**
         * 插入结点到双向链表末尾
         *
         * @param newNode
         */
        public void addLast(SNode<T> newNode) {
            if (isEmpty()) {
                head = newNode;
                head.next = null;
                head.pre = null;
                size++;
            } else {
                SNode<T> temp = head;
                // 找到双向链表最后一个有效结点
                while (temp.next != null) {
                    temp = temp.next;
                }
                // 将新结点加入双向链表
                addAfter(temp, newNode);
            }
        }

        /**
         * 将新的节点插入到指定节点后
         *
         * @param preNode 指定节点
         * @param newNode 新的节点
         */
        public void addAfter(SNode<T> preNode, SNode<T> newNode) {
            // 要插入到链表末尾时,不需要维护下一个结点的前驱指针
            if (preNode.next != null) {
                preNode.next.pre = newNode;
            }
            newNode.next = preNode.next;
            newNode.pre = preNode;
            preNode.next = newNode;
            size++;
        }
        /**
         * 将结点插入到新结点前
         */
        public void addPre(SNode<T> afterNode, SNode<T> newNode) {
            // 要插入到链表第一个结点时候,不用维护前一个的后继
            if (afterNode.pre != null) {
                afterNode.pre.next = newNode;
            } else head = newNode;
            newNode.pre = afterNode.pre;
            newNode.next = afterNode;
            afterNode.pre = newNode;
            size++;
        }
        /**
         * 删除数据域为指定值的元素
         *
         * @param e
         */
        public void del(T e) {
            SNode<T> temp = head;
            while (temp != null) {
                if (temp.data.equals(e)) {
                    // 维护 head,head 永远指向双向链表第一个有效结点
                    temp.next.pre = temp.pre;
                    if (temp == head) {
                        head = head.next;
                        head.pre = null;
                    } else {
                        temp.pre.next = temp.next;
                    }
                    return;
                }
                // temp 向后移
                temp = temp.next;
            }
        }

        /**
         * 删除指定位置的结点
         *
         * @param k
         */
        public void del(int k) {
            SNode<T> delNode = find(k);
            delNode.next.pre = delNode.pre;
            if (delNode == head) {
                head = head.next;
                head.pre = null;
            } else {
                delNode.pre.next = delNode.next.next;
            }
        }

        public SNode<T> findO(T x) {
            SNode<T>p = head;
            while (p != null && !p.data.equals(x)) p = p.next;
            assert p != null;
            return p;
        }

        /**
         * 找到双向链表第 k 个结点
         *
         * @param k k 从 0 开始
         * @return
         */
        public SNode<T> find(int k) {
            if (k > size || k < 0) {
                throw new RuntimeException("传入的参数 k 必须大于等于零并且小于等于链表的长度 size");
            }
            int cnt = 0;
            SNode<T> t = head;
            while (cnt != k) {
                cnt++;
                t = t.next;
            }
            return t;
        }

        /**
         * 打印单链表所有有效节点
         *
         * @return
         */
        public String printAll() {
            StringBuilder sb = new StringBuilder();
            SNode<T> temp = head;
            while (temp != null) {
                sb.append(temp.data);
                sb.append(" ");
                temp = temp.next;
            }
            return sb.toString();
        }
    }
     public static void main(String[] args) throws Exception{
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
//        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
        HashMap<Integer, SNode<Integer>>loc = new HashMap<>();
        int n = Integer.parseInt(in.readLine());
        int x = Integer.parseInt(in.readLine());
        DoubleLinkedList<Integer> list = new DoubleLinkedList<>();
//        HashSet<Integer>set = new HashSet<>();
         SNode<Integer> cur = new SNode<>(x);
         loc.put(x, cur);
         list.addLast(cur);
        for (int i = 0; i < n - 1; i++) {
            String[] input = in.readLine().split(" ");
            int a = Integer.parseInt(input[0]);
            int b = Integer.parseInt(input[1]);
            int c = Integer.parseInt(input[2]);
            // b是已知结点,

            SNode<Integer> preNode = loc.get(b);
            cur = new SNode<>(a);
            loc.put(a, cur);
            if (c == 1) {
                // 把当前结点放在前一个结点的右边。
                list.addAfter(preNode, cur);
            }
            else {
                // 把当前结点放在前一个结点的左边
                list.addPre(preNode, cur);
            }
        }
//        out.write(list.printAll());
//         System.out.println();
        System.out.println(list.printAll());
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值