五、线性表(堆、栈、链表)

线性表(栈、队列、链表)

1. 栈、队列、链表的比较

属性栈 Stack队列 Queue链表 LinkedList
进出顺序先进后出先进先出无所谓,都可以
增加元素压栈Push(进入栈顶)入队Enqueue(进入队尾)插入Insert(插入任意位置)
减少元素弹栈Pop(取出栈顶元素)出队Dequeue(取出队头元素)删除节点Delete(从任意位置删除)
高级操作深度优先搜索(DFS)广度优先搜索(BFS)--------

2. 栈、队列、链表的基本操作

  • 队列链表有多种实现方式,比如可以用数组或者链表实现。考试时,肯定只要求:采用数组实现栈和队列,用节点实现链表。因此,以下均采用数组实现栈和队列,采用节点实现链表。

  • 此部分虽然简单,但属于重点内容,必考。

2.1 栈

class Stack{
    // 用数组实现的栈
    private int data[];
    // 栈顶指针,指向栈顶部的元素,因此-1 <= top <= data.length - 1
    private int top;

    // 构造器
    public Stack(int maxSize) {
        data = new int[maxSize];
        top = -1; // 注意这个-1,当空栈时,栈顶指针是-1,不是0
    }

    // 压栈
    public void push(int x) throws Exception{
		// 如果栈满了,那么就不能再压栈了,操作失败
        if (top == data.length-1)
            throw  new Exception("Expection : Stack Overflow");
        // 栈顶指针上移,然后在栈顶添加元素x
        data[++top] = x;
    }
    
    // 弹栈
    public int pop() throws Exception{
    	// 如果是空栈,那么不能弹栈
        if (isEmpty())
            throw new Exception("演示 Expection : Stack Underflow");
        // 返回栈顶元素,栈顶指针下移
        return data[top--];
    }
    
    // 判空操作
    public boolean isEmpty(){
        return top == -1;
    }
}

2.2 队列

class Queue {
    // 用数组实现队列
    private double[] data;
    // 需要两个指针,队头指针、队尾指针
    private int head;
    private int tail;
    
    // 构造器
    public Queue(int size){
        data = new double[size];
        head = -1; // 队列为空时,head记为-1
    }
    
    /*
     * 设计思想 :
     *     队头指针       ↓
     *     数组下标   0   1   2   3   4   5
     *     队尾指针                   ↑
     * 此时,队列内的元素从队头到队尾依次为:1,2,3。(不包含4,注意)
     */
    
    // 判空
    boolean isEmpty(){
        return head == -1;
    }
    
    
	// 判满
    public boolean isFull(){
        return head == tail;
    }
    
    
    public void enqueue(double e) throws Exception{
        // 如果队列满了,就不能入队了
        if (isFull()){
            throw new Exception("Queue overFlow !!!");
        }
        
        // 如果队列为空,那么此时队头为-1,我们需要把队头和队尾初始化为0
        if (isEmpty()){
            head = tail = 0;
        }
        
        
        if (tail != data.length-1){
            // 在队尾入队
            data[tail++] = e;
        }
        
        else {
            // 如果队尾指针触及到数组右界,那么队尾接下来指向0
            data[tail] = e;
            tail = 0;
        }
    }
    
    // 出队
    public double dequeue() throws Exception{
        //空队列不能出队
        if (isEmpty()){
            throw new Exception("Queue underFlow!!!");
        }
        
        // 出队元素的值
        double res = data[head];
        
        if (head != data.length - 1) head ++;
        // 如果队头指针触及到数组有界,那么队头接下来指向0
        else head = 0;
        
        // 如果出队后队列空了,那么令head=-1,作为空队列的标记
        if (head == tail) head = -1;
        
        return res;
    }
}

2.3 双向链表

在这里插入图片描述

class Node {
    Node prev; // 前驱指针
    Node next; // 后继指针
    int key;   // 节点的值
}

class LinkedList {
    // 头节点
    // 注意,头节点不存放元素
    Node nil;
    
    // 构造器
    LinkedList() {
        this.nil = new Node();
        this.nil.prev = nil;
        this.nil.next = nil;
    }

    // 在index位置插入元素key
    void insert(int index, int key) {
        Node node = new Node();
        node.key = key;
        Node x = nil.next; // 头节点不存放元素,因此直接从下一个元素开始
        // 通过下面这个循环,前往链表中index的位置。因此在链表中插入元素的时间复杂度是O(n)
        while(index > 0){
            x = x.next;
            index --;
        }
        
        // 看着上面的图片,好好想一想链表连接方式的变化
        // 动手画一画,想不清楚再来问,这几行代码是靠理解的
        x.prev.next = node;
        node.prev = x.prev;
        node.next = x;
        x.prev = node;
    }
    
    // 删除节点元素e
    void delete(int e) throws Exception{
        Node node = nil.next; // 头节点不存放元素,因此直接从下一个元素开始
        
        while(node != nil){
            if (e == node.key){
                // 看着图片,好好想一想链表连接方式的变化
                node.prev.next = node.next;
                node.next.prev = node.prev;
                return;
            }
            node = node.next;
        }
        
        // 如果跳出循环都没有return,那么就是找不到元素e
        throw new Exception("No such an element!!!" );
    }
    
    //搜索元素e
    Node search(int e){
        Node cur = nil.next;
        return search(nil, e);// 调用下面的private Node search()函数
    }
    private Node search(Node cur, int e){
        if (cur.key != e && cur !=nil){
            //递归搜索
            return search(cur.next,e);
        }
        else if (cur ==nil){
            //达到链表尽头,却还是没找到元素e
            return null;
        }
       		//找到元素e了,返回
        else return cur;
    }
}

3. DFS与BFS

在二叉树中介绍。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值