目录
在上一篇文章里详细介绍了顺序表的定义与用法,这篇文章则重点介绍链表的详细用法与优缺点
一、链表的定义
链表又叫做线性表的链式存储,由一个个的节点(或者结点)组成,类似生活中的火车车厢一节节的串在一起。链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。
链表中的每一个结点包含两部分:一个叫数据域:存储数据元素信息,另外一个叫指针域:存储下一个节点的存储地址。
对于线性表来说,总得有个头有个尾,链表也不例外。我们把链表的第一个节点前设一个节点,称为头节点。头节点的数据域可以不存储任何信息,头节点的指针域存储指向第一个节点的指针。线性链表的最后一个节点的指针域为空(用NULL表示)
带头单向非循环链表示例图:
二、链表的种类
链表根据是否带有头节点,不带头节点,单向或者双向,循环或者非循环可以组合成8种情况:
带头 双向 循环链表 不带头 双向 循环链表
带头 双向 非循环链表 不带头 双向 非循环链表
带头 单向 循环链表 不带头 单向 循环链表
带头 单向 非循环链表 不带头 单向 非循环链表
其中 双向值得是带有2个指针域,一个指针域指向下一节点的存储地址,另一个指针域指向上一节点的存储地址。
三、不带头单向非循环链表实现
(1)创建链表
public class ListNode{
public int val; //创建数据域
public ListNode next; //创建指针域,//存储下一个节点的地址
public ListNode head;//代表单链表的头结点的引用
public ListNode(){
this.val = val;
}
public void createListNode(){ //创建一个链表
ListNode listnode1 = new ListNode(12);//12为第一节点的val值
ListNode listnode2 = new ListNode(15);
ListNode listnode3 = new ListNode(23);
ListNode listnode4 = new ListNode(44);
listnode1.next = listnode2;
listnode2.next = listnode3;
listnode3.next = listnode4;
this.head = listnode1;
}
}
(2)遍历打印链表元素
public void display() {
ListNode cur = head;
while(cur!=null){
System.out.print(cur.val+" ");
cur=cur.next;
}
System.out.println();
}
(3)头插法
public void addFrist(int data){
ListNode node = new ListNode(data);//创建一个新的节点进行头插
node.next=this.head;
this.head=node;
}
(4)尾插法
public void addLast(int data){
ListNode node = new ListNode (data);
if(this.head==null){
this.head = node;
}else{
ListNode cur = head;
while(cur.next!=null){//找到最后一个节点,因为最后一个节点的next为null
cur=cur.next;
}
cur.next=node;
}
}
(5) 任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data){
ListNode node =new ListNode(data);
if(index < 0 || index > size() ){
System.out.println("插入位置不合法");
return;
}
if(index ==0){//头插
addFirst(data);
return;
}
if(index == size()){//尾插
addLast(data);
return;
}
while(index-1 !=0){ //找到下标index的前一个位置即index-1
ListNode cur = head;
cur=cur.next; //当循环结束时,此时cur指向index-1的节点
index--;
}
node.next=cur.next; //先绑定后面节点
cur.next=node;
}
(6)查找是否包含关键字key是否在单链表当中
public boolean contains(int data){
ListNode cur = head;
while(cur != null){
if(cur.val == key){
return true;
}
cur=cur.next;
}
return false;
}
(7)删除所有值为key的节点
public void removeAll(int key){
ListNode cur = head;
if(head == null){
return null;
}
while(head !=null && head.val == key){ //先判断头节点的val是否等于data
head = head.next;
}
while(cur != null){
while(cur.next != null && cur.next.val == key){ //此时已确认了头节点不等于data,从第二节点开始循环判断
cur.next=cur.next.next;
}
cur=cur.next;
}
}
public void remove (int key){
if(head == null){
return null;
}
if( head.val == key){
head = head.next;
return;
}
ListNode cur = head;
while( cur.next!=null){ //找到key的前一个节点
if( cur.next.val == key){
return;
}
cur=cur.next;
}
cur.next=cur.next.next; //删除key所在节点
}
(9)获取单链表的长度
public int size(){
int count=0;
while(cur != null){
count++;
cur=cur.next;
}
return count;
}
四、不带头双向非循环链表实现
public class MyLinkedList {
//头插法
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(){}
}