目录
2.5.2 删除所有和key值相等的节点(面试可能会考,重点)
1.链表的概念和分类
1.1概念
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
链表结构包括两部分:一是数据域,二是指针域,称为引用域!其中,数据域用来存放数据,它可以是基本数据类型,也可以是引用数据类型,不论是前者还是后者,在面向对象编程当中通通叫做对象;引用域用来存放地址,这个地址指向下一个链表结点或前一个链表结点,对于引用域的引用变量可以是一个也可以是两个,只有一个引用变量,则该链表为单链表,有两个引用变量,一个指向前驱结点,另一个指向后继结点,则该链表为双链表。
1.2分类
链表主要依据以下三点进行分类:
1.带头与不带头 2.循环与不循环 3.单链表和双链表
因而可将链表分为8类: 带头非循环单链表、 不带头非循环单链表、带头循环单链表、不带头循环单链表、带头非循环双链表、不带头非循环双链表、不带头循环双链表
1.3 链表具体结构
定义 链表中的数据值为val,引用域指向下一节点的变量名为next,指向前一个节点的引用变量名为prev,单链表的最后一个节点next指向null,双链表的最后一个节点与第一个节点的prev指向null
1.4 链表与顺序表的区别(面试常考)
顺序表的物理结构是连续的,逻辑结构也是连续的,它的优点是支持随机访问,获取和修改一个数据非常地方便,缺点是插入,删除元素不方便,空间利用率不高,可能存在大量空间浪费。
链表的物理结构不连续,逻辑结构连续,它完美解决了顺序表的缺点,它的优点是插入,删除元素方便,空间利用率高,随取随用,缺点是访问不方便,不支持随机访问。
2.单链表的增删查改
基本方法列表
public class SList {
public ListNode head;
//头插法
public void addFirst(int data){
}
//尾插法
public void addLast(int data){
}
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data){
}
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key){
}
//删除第一次出现关键字为key的节点
public void remove(int key){
}
//删除所有值为key的节点
public void removeAllKey(int key){
}
//得到单链表的长度
public int size(){
}
//打印链表数据
public void display(){
}
//链表销毁
public void clear(){
}
}
2.1单链表的数据插入
基本变量和结构方法的准备
class ListNode {//ListNode代表一个节点
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;//该构造方法是为了让下面new一个对象时,直接给val进行赋值
}
}
public class MylinkedList {
//head为链表的头引用
public ListNode head;
//各类方法。。。。
}
2.1.1 头插法
头插法:在第一个节点前面插入数据,即将插入的数据的节点和后一个节点连接,并将头引用指向新插入的数据节点,主要实现的代码 (1)node.next=head.next (2)head=node
代码实现:
//头插法
public void addFist(int data) {
ListNode node = new ListNode(data);
node.next=this.head;
this.head=node;
// if (this.head == null) {
// this.head = node;
// }else {
// node.next = head;
// this.head = node;
// }
}
2.1.2 尾插法
尾插法则需要先遍历链表找到最后一个节点,即cur.next为null,然后再将新节点插入到最后一个节点后
public void addLast(int val){
ListNode node=new ListNode(val);
if(this.head==null){
this.head=node;
}
ListNode cur=this.head;
while(cur.next!=null){
cur=cur.next;
}
cur.next=node;
}
2.1.3 任意位置插入
//找到打算插入值的index-1位置节点地址,在index-1和index位置中间
//插入,则插入的值的节点位置刚好为index
public ListNode findIndex(int index){
ListNode cur=this.head;
if(index-1!=0){
cur=cur.next;
index--;
}
return cur;
}
public void addIndex(int index,int data){
if(index<0||index>size()){
System.out.println("位置不合法");
return;
}
//如果index=0则头插法
if(index==0){
addFirst(data);
return;
}
//如果index=size则尾插
if(index==size()){
addLast(data);
return;
}
//index-1位置的节点
ListNode cur=findIndex(index);
//定义一个node节点并将data存入其中
ListNode node=new ListNode(data);
//新添加的节点和后面节点链接
node.next=cur.next;
//前面节点和node链接
cur.next=node;
}
2.2 单链表的打印
public void display(){
ListNode cur=this.head;
while(cur!=null){
System.out.println(cur.val+" ");
cur=cur.next;
}
System.out.println();
}
2.3单链表数据的查找
public boolean contains(int key){
ListNode cur=this.head;
while(cur!=null){
if(cur.val==key){
return true;
}
cur=cur.next;
}
return false;
}
2.4获取单链表的数据个数
public int size() {
int count = 0;
ListNode cur = head.next;
while (cur != null) {
cur = cur.next;
count++;
}
return count;
}
2.5 单链表数据的删除
2.5.1 删除链表中第一次出现的目标值
//删除第一次出现关键字为key的节点
public void remove(int key){
if(this.head==null){
System.out.println("单链表为空,不能删除");
return;
}
//如果头节点为要删除的节点
if(this.head.val==key){
this.head=this.head.next;
return;
}
//cur表示要删除的节点
ListNode cur=this.head.next;
ListNode prev=this.head;
while(cur!=null){
if(cur.val==key){
//如果cur为要删除的节点,则可将前驱与cur。next链接
prev.next=cur.next;
return;
}
//如果还没有找到,则cur的值赋值给前驱,cur值向后走寻找要删除的值
prev=cur;
cur=cur.next;
}
System.out.println("未找到目标节点!");
}
2.5.2 删除所有和key值相等的节点(面试可能会考,重点)
//删除所有链表中的目标值
public void removeAllkey(int key){
if(this.head==null){
return;
}
//当头节点的值和key值相等时
while(this.head.val==key){
//让头节点的值变为下一节点的值,由于是删除所有,因而
//还需要继续往下去寻找
this.head=this.head.next;
if(this.head==null){
return;
}
}
//继续向后寻找
ListNode cur=this.head.next;
ListNode prev=this.head;
while(cur!=null){
if(cur.val==key){
prev.next=cur.next;
//和上面的区别是找到后cur仍需要继续向后走
cur=cur.next;
}
else{
//如果没有找到则前驱prev和待删除的cur往后走
prev=cur;
cur=cur.next;
}
}
}
2.5.3 单链表的销毁
// 清空链表
public void clear(){
while(this.head!=null){
ListNode curNext=head.next;
this.head=null;
this.head=curNext;
}
}
}