链表先从顺序表开始讲起

顺序表可以称之为一个数组,其具备数组的一切属性

我认为其存在就是为了与链表进行比较

 

作为一个数组,数组长度一旦创建就没办法修改,所以容量问题,只能通过copyof功能拷贝到另外一个数组上去

而链表,由于其现用现申请容量的特性,变相的节省了表占空间

但是由于其不确定性,同时也给add与delete方法创造了一定的难度

不像是数组具有序号的操作属性

 

 

 

链表,可以称之为一个带有指针的数组,分为数据域、指针域

(单向无头)单链表:

//class Node是链表中的一个基本块,也相当于一个元素的结构体

class Node{

    public int val;
   public Node next;

   public Node(int val){

        this.val = val;
   }

链表

尾插法

//头插法

public void addFirst(int data){

    Node tmp = new Node(data);//创建一个块,其数据域赋上data
   tmp.next = head;//让创建的块的指针域链上原表中的head,相当于在head前添加了一个元素
   head = tmp;//当前链表的head是新的head传过来
}

 

 

//尾插法
public void addLast(int data){

    Node tmp = new Node(data);//创建一个块,其数据域赋上data
    //如果原链表为空,则直接给此时为null的head

if(this.head == null) {

        this.head = tmp;
   }else {//原来有值

        Node cur = this.head;//临时值
       while (cur.next != null) {//遍历链表找到最后一个元素

            cur = cur.next;
       }

        cur.next = tmp;//将新的块链到最后
   }

}

 

//中间插入
public Node searchIndexSubOne(int data){

    int count = 0;
   Node tt = head;
   while(count != data-1){//data个数据中间要走data-1次

        count++;
       tt = tt.next;
   }

    return tt;
}

 

//查找功能

//查找是否包含关键字为key是否在单链表当中
public boolean contains(int key){

    Node tmp = head;
   while(tmp.next != null){//遍历链表

        tmp = tmp.next;
       if(tmp.val != key){//不存在等于key的值

        return false;
       }

    }

    return true;
}

 

 

//删除第一次出现关键字为key的节点,
public void remove(int key){

    Node tmp = head;
   Node tmpNext =head.next;
   if(head == null){

        return;
   }

    if(head.val == key){

        head = head.next;
   }

    while(tmp.next != null){

        tmpNext = tmpNext.next;
       tmp = tmp.next;
       if(tmpNext.val == key){

            tmp.next = tmpNext.next;
           tmpNext = null;
           return;
       }

    }

}

 

 

//删除所有值为key的节点
public void removeAllKey(int key){

    Node pre = new Node(-1);//创建一个新的pre块
   pre.next = head;//pre链到head前边,作为前驱结点
   Node next = head.next;
   Node cur = head;
   while(cur != null) {

        if(cur.val == key) {

            pre.next = next;//找到了cur的数据域为key,则将其前驱结点直接链到他的后继结点next上相当于给他跳了
       }

        pre = cur;//把前驱后移,注意不能直接pre = pre.next因为原来链表pre与cur之间已经没有指针了,直接给过去
       cur = cur.next;//继续遍历
       if(next.next != null) {

            next = next.next;//next到头了
       }

    }

}

 

 

//得到链表长度

//计数器+遍历实现

public int size(){

    int count = 0;
   Node tmp = head;
   while(tmp.next != null){

        count++;
       tmp = tmp.next;
   }

    return count;
}

 

 

 

//打印
public static void display(Node head){

    while (head != null) {

        System.out.print(head.val+" ");
       head = head.next;
   }

}

 

 

//清除

//应该是错的下次重写

public void clear(){

    Node tmp = head;
   Node tmpNext = head.next;
   while(tmpNext.next != null){

        tmp = tmp.next;
       tmp.next = null;
   }

    head = null;
}

 

链表:

以节点为单位存储,不支持随机访问

适合添加、删除,因为可以随时申请随时使用内存空间,删除则是断链(其实是因为数组操作起来太麻烦,所以比较之下链表更方便)

 

顺序表:

空间连续,中间或者前边

适合查找、修改,因为可以拿着下标去锁定目标

顺序表

其实就是数组

只不过在顺序表增加了类的概念,所以在类中定义,属性与调用方式改变了

 

链表一共有八种

单向,双向

带头,不带头

循环,非循环

 

与顺序表主要的区别:表中元素由两个部分组成,数据域,指针域

数据域:用于存储该节点的数据

指针域:用于存储下一个节点的地址,起指向作用。注意:在此处体现出Java与C语言的区别,在C语言对其的讲解中,指针域存储了一个指针,指向下一个节点,当然实际作用哦是一样的只是概念上的差别。

 

以第一个节点称之为head,头节点,但不是带头链表的头节点

在Node类中,先定义一个head,不将其初始化具体数据,因为链表还没有定义,所以无法确定头节点存储的内容。

在psvm中,定义完链表,再this.head = Node1;

注意:psvm要求main函数必须是静态(static)的,但是你的head定义未必是静态的,在静态方法中,无法定义非静态变量

所以在类中,应该public static int head ;调用时,直接head = Node1;