链表先从顺序表开始讲起
顺序表可以称之为一个数组,其具备数组的一切属性
我认为其存在就是为了与链表进行比较
作为一个数组,数组长度一旦创建就没办法修改,所以容量问题,只能通过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的headif(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;