从链表到栈与队列

List可以说是一个非常基础,非常实用的结构,因为舍弃了随机读取,所以可以快速的实现插入。

我们来看看这样的好处和不足

显然查找变得非常的困难,我们每次打算访问时,都有可能遍历每一个节点。
但是,实现插入或者删除却比较方便和简单

我们来讨论一下链表和顺序表的不同

首先,我们来看看访问的不同
数组 直接通过下标 因为其连续性
而链表却没有这种连续性,所以我们只能通过计数来找到这个值,这是通过索引来查找,但如果我们是要找到某个键值的话,那两者都是最多将整个表的每个元素访问一次,这里不存在性能上的差异

而如果我们要在中间或者是在开头(某个位置)进行一个插入的话,链表具有绝对的优势

下面我们来看链表的具体实现方式

我们可以发现,链表的一个节点所存的并非只有值,而还有一个引用,这个引用的目的就是找到下一个值(i+1)。
实际上就是一个指针域和一个键值域

实际上,链表并非只有一个引用,可以有两个,比如指向前一个节点和后一个节点的引用。而实际上我们还可以有更多(这个时候的链表实际是已经不是线性结构了,但如果从某个特殊的角度看,却还是一个线性的结构,这里我们不再做讨论)

单向链表
这里我们只是简单的讲讲链表的逻辑,从而忽视了指针和值的问题
下面我们先来看节点的实现

class Node{
	int val;
	Node nex;
}

这就是一个最简单的定义了
val表示的是这个链表的节点的值,我们可以很简单的将它变成其他形式,这里不再讨论。
nex是一个指针,但这里我们用引用来表述,它表示的就是下一个节点。
实际是我们还需要一个链表的头部,通过这个头部来遍历整个链表

这里我们用leetcode的一道题目来具体讲讲链表的实现
这里是传送门
题目具体要求我们实现这几个功能

get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val  的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
class MyLinkedList {
    class ListNode{
        public ListNode(int val){
            this.val=val;
            this.next=null;
        }
        public int val;
        public ListNode next;
    }
    ListNode head;
    ListNode end;
    int length;
    /** Initialize your data structure here. */
    public MyLinkedList() {
        head=null;
        end=null;
        length=0;
    }
    /** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
    public int get(int index) {
        print();
        if(index>=length) return -1;
        ListNode cur=head;
        for(int i=0;i<index;i++){
            cur=cur.next;
        }
        return cur.val;
        
    }
    
    /** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
    public void addAtHead(int val) {
        ListNode newNode=new ListNode(val);
        newNode.next=head;
        head=newNode;
        if(end==null) end=head;
        length++;
        print();
    }
    
    /** Append a node of value val to the last element of the linked list. */
    public void addAtTail(int val) {
        ListNode newNode=new ListNode(val);
        if(end!=null){
            end.next=newNode;
            end=newNode;
        }else{
            end=new ListNode(val);
            head=end;
        }
     
        length++;
        print();
    }
    
    /** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
    public void addAtIndex(int index, int val) {
        
  
        if(index<0||index>length);
        else{
           
            if(index==0){
                addAtHead(val);
            }else if(index==length){
              //  System.out.println("@#@#@  end "+end.val);
                addAtTail(val);
                //print();
        
            }else{ 
            
                ListNode newNode=new ListNode(val);
                ListNode cur=head;
                for(int i=0;i<index-1;i++){
                    cur=cur.next;
                }
                ListNode nex=cur.next;
                cur.next=newNode;
                newNode.next=nex; length++;
            }
       
        }
      
    }
    
    /** Delete the index-th node in the linked list, if the index is valid. */
    public void deleteAtIndex(int index) {
    
    
        if(index<0||index>=length);
        else{
            if(index==0){
                head=head.next;
            }else{
                ListNode cur=head;
                for(int i=0;i<index-1;i++){
                   cur=cur.next;
                }
                if(cur.next.next==null){
                    end=cur;
                    length--;
                    end.next=null;
                }else{
                    length--;
                    cur.next=cur.next.next;
                }
            }
        }
    }
}

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList obj = new MyLinkedList();
 * int param_1 = obj.get(index);
 * obj.addAtHead(val);
 * obj.addAtTail(val);
 * obj.addAtIndex(index,val);
 * obj.deleteAtIndex(index);
 */

然额作者太懒并不打算写注释,所以将就看吧

关于链表有非常多的算法,但我们在这里略去,只讲一些非常基础的算法实现
链表判换
倒置链表

这个也是有生之年系列了

有时候我们希望得到的链表是一个环,这个时候我们只要将最后一个节点的下一个节点连到表头就可以了。

双向链表

在实现了链表以后
我们可以轻松的实现栈
这里下次再写吧

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值