目录
4.1public void addFirst(int data)//头插法
4.2public void addLast(int data)//尾插法
4.4public void Index(int index,int data)//插入节点
getIndexPos(int index)//返回当前插入节点的位置
4.5public boolean contains(int tofind)//查询是否包含关键字tofind
4.6public void display()//打印链表中的所有元素
4.7public void Remove(int toRemove)//删除单个节点
4.8private LinkedNode gettoRemovePrev(int toRemove)//找到要删除的前一个元素
public void Remove(int toRemove)//删除节点方法实现
线性表
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物
理上存储时,通常以数组和链式结构的形式存储。
eg.常见的线性表:顺序表、链表、栈、队列、字符串
单链表:
一段物理地址不一定连续,逻辑上一定连续的存储单元存储数据结构
单链表接口:
public interface ILinked {
//头插法
void addFirst(int data);
//尾插法
void addLast(int data);
//任意位置插入,第一个数据节点为0号下标
boolean addIndex(int index, int data);
//查找是否包含关键字key是否在单链表当中
boolean contains(int key);
//删除第一次出现关键字为key的节点
int remove(int key);
//删除所有值为key的节点
void removeAllKey(int key);
//得到单链表的长度
int getLength();
void display();
void clear();
}
1创建节点类Node:
是MySingleListImpl的内部类
a.节点类引用next:引用本质上是一个指针,也就是地址
private Node next;
b.整型变量,名称为data
c.利用构造函数对属性进行初始化
public Node(){//无参构造
this.data=-1;
this.next=null;
}
public Node(int data){//有参构造
this.data=data;
}
d.内部类Node类的代码:
class Node {
private Node next;
private int data;
//node的data域没有值,提供一个不带有参数的构造函数
public Node() {
//用-1去标识data域中的数据
this.data = -1;
this.next = null;
}
//实体结点应该有data值
public Node(int data) {
this.data = data;
}
}
2 属性
a.head:结点类属性,表示链表的头结点
private Node head;
3一些内存变化
a.创建node引用时内存的变化:(LinkedNode node=new LinkedNode)
b.node引用指向next时内存的变化:(node=node.next)
4方法实现
4.1public void addFirst(int data)//头插法
通俗点讲就是从链表的头部插入节点。这时候我们要考虑两种情况:
a.头节点为空,插入的节点就指向链表的头节点
this.node=this.head;
b.头节点不为空,插入的节点指向头节点的下一个节点,头节点指向node
this.node=this.head.next;
this.head=node;
方法代码:
public void addFirst(int data){
Node node=new Node(data);
if(this.head==null){
this.node=this.head;
return;
}else{
this.node=this.head.next;
this.head=node;
return;
}
4.2public void addLast(int data)//尾插法
就是从链表的尾部插入节点。
思想:
这时候要考虑链表的头节点为空的情况
a.头节点为空,和头插法类比。
b.头节点不为空,new 一个cur对象,将当前头节点的定义为cur,遍历cur直到cur.next为空说明链表遍历结束。
此时插入node节点,使得cur.next指向node
方法代码:
public void addLast(int data){
Node node=new Node(data);
if(this.head==null){
this.head=this.node;
}else{
Node cur=this.head;
while(cur!=null){
this.cur=this.cur.next;
}
this.cur.next=this.node;
}
4.3public int size( )//链表长度
思想:创建计数变量count,new 一个Node对象cur 遍历单链表,可以得出链表的长度。
方法代码:
public int size( ){
int count=0;
if(this.head==null){
return 0;
}else{
Node cur=this.head;
while(this.cur!=null){
count++;
this.cur=this.cur.next;
}
return count;
}
4.4public void Index(int index,int data)//插入节点
思想:
1 头插
2 尾插
3 中间插
在实现插入方法前我们需要找到被插入节点的前驱
这里引入另一个方法
getIndexPos(int index)//返回当前插入节点的位置
思想:
a.new 一个Node类对象cur,遍历单链表直到index位置退出循环
b.中间插:
也就是node节点插入到index(目标插入点)-1的后面,利用找到插入节点位置的方法,找到插入节点的前驱prev,再将node的next指向prev的next,prev的next指向node
方法代码:
public void Index(int index,int data){
Node node=new Node(data);
int len=size();
if(index<0||index>len){
return;
}
if(index==0){
addFirst(data);
return;
}
if(index==len){
addLast(data);
return;
}
Node prev=getIndexPos(index-1);
node.next=prev.next;
prev.next=node;
}
4.5public boolean contains(int tofind)//查询是否包含关键字tofind
思想:Node 类节点cur遍历链表,当cur.data==tofind说明成功找到,返回true,否则返回false
方法代码:
public boolean contains(int tofind){
Node cur=this.head;
while(cur!=null){
if(this.cur.data==tofind){
return true;
}
this.cur=this.cur.next;
}
return false;
}
4.6public void display()//打印链表中的所有元素
public void display()
{
System.out.println("[");
LinkedNode cur=this.head;
while(cur!=null){
System.out.print(cur.data);
if(node.next!=null){
System.out.print(",");
}
cur=cur.next;
}
System.out.println("]");
}
for循环:
public void display(){
System.out.println(“[“);
for(LinkedNode node=this.head;node!=null;node=node.next){
System.out.print(node.data);
if(node.next!=null){
System.out.print(”,“);
}
}
System.out.println(“]”);
}
4.7public void Remove(int toRemove)//删除单个节点
思想:
1 检查是否是空链表
2 检查删除的是否是头节点
3 找到要删除的前一个元素,将要删除的前一个元素指向被删除元素的下一个元素。
4.8private LinkedNode gettoRemovePrev(int toRemove)//找到要删除的前一个元素
1 先判断是不是空链表
2 prev不为空时遍历单链表
要删除的节点toRemove等于prev.next的data域时,返回prev
private LinkedNode gettoRemovePrev(int toRemove){
if(this.head==null){
return;
}
LinkedNode prev=this.head;
while(prev!=null){
if(prev.next.data==toRemove){
return prev;
}
prev=prev.next;
}
return;
}
public void Remove(int toRemove)//删除节点方法实现
public void Remove(int toRemove){
if(this.head==null){
return;
}
if(this.head.data==toRemove){
this.head==this.head.next;
}
LinkedNode prev=gettoRemovePrev(toRemove);
node=prev.next;
prev.next=node.next;
}
完整代码:
public class MySingleListImpl implements ILinked {
//内部类
class Node {
private Node next;
private int data;
//node的data域没有值,提供一个不带有参数的构造函数
public Node() {
//用-1去标识data域中的数据
this.data = -1;
this.next = null;
}
//实体结点应该有data值
public Node(int data) {
this.data = data;
}
}
private Node head;
public MySingleListImpl() {
this.head = new Node();
this.head.next = this.head;
}
//头插法
@Override
public void addFirst(int data) {
Node node = new Node(data);
node.next = this.head.next;
this.head.next = node;
}
//尾插法
@Override
public void addLast(int data) {
//从头开始找
Node cur = this.head;
while (cur.next != this.head) {
cur = cur.next;
}
//拿到一个结点实例
Node node = new Node(data);
node.next = this.head;
cur.next = node;
}
private void checkIndex(int index) {
if (index < 0 || index > getLength()) {
throw new UnsupportedOperationException("下标不合法");
}
}
//任意位置插入,第一个数据节点为0号下标
@Override
public boolean addIndex(int index, int data) {
checkIndex(index);
Node cur = this.head;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
Node node = new Node(data);
node.next = cur.next;
cur.next = node;
return true;
}
//查找是否包含关键字key是否在单链表当中
@Override
public boolean contains(int key) {
Node cur = this.head.next;
while (cur != head) {
if (cur.data == key) {
return true;
}
cur = cur.next;
}
return false;
}
private Node searchPrev(int key) {
int oldData = 0;
Node prev = this.head;
while (prev.next != this.head) {
if (prev.next.data == key) {
return prev;
}
prev = prev.next;
}
return null;
}
@Override
public int remove(int key) {
Node prev = searchPrev(key);
if (prev == null) {
//return -1;
throw new UnsupportedOperationException("key不存在前驱");
}
int oldData = 0;
Node delNode = prev.next;
oldData = delNode.data;
prev.next = delNode.next;
return oldData;
}
//删除所有值为key的节点
@Override
public void removeAllKey(int key) {
Node prev = this.head;
Node cur = prev.next;
while (cur != this.head) {
if (cur.data == key) {
prev.next = cur.next;
cur = cur.next;
} else {
prev = cur;
cur = cur.next;
}
}
}
//得到单链表的长度
@Override
public int getLength() {
Node cur = this.head.next;
int count = 0;
while (cur != this.head) {
cur = cur.next;
count++;
}
return count;
}
@Override
public void display() {
Node cur = this.head.next;
while (cur != this.head) {
System.out.print(cur.data + " 、");
cur = cur.next;
}
System.out.println();
}
@Override
public void clear() {
while (this.head.next != this.head) {
Node cur = this.head.next;
this.head.next = cur.next;
cur.next = null;
}
this.head = null;
}
}
主函数:
public class Test3
{
public static void main(String[] args) throws Exception {
MySingleListImpl cHeadSingleList = new MySingleListImpl();
cHeadSingleList.addFirst(1);
cHeadSingleList.addFirst(3);
cHeadSingleList.addFirst(105);
cHeadSingleList.addFirst(3);
cHeadSingleList.addFirst(9);
cHeadSingleList.display();
cHeadSingleList.addIndex(0, 3);
cHeadSingleList.addLast(100);
cHeadSingleList.display();
System.out.println(cHeadSingleList.contains(135));
cHeadSingleList.removeAllKey(3);
cHeadSingleList.display();
cHeadSingleList.clear();
Thread.sleep(1000);
}
}
运行结果: