链表Linked list

本文详细介绍了链表(包括单向、双向和循环链表)的定义、不同类型的插入和删除操作(如随机访问性能、首尾添加、索引查找与修改),以及使用哨兵节点的优势。同时涵盖了遍历链表的各种方法,如普通遍历、函数接口和迭代器。
摘要由CSDN通过智能技术生成

概述

定义:元素储存上并不连续

分类

单向链表:每个元素只知道下一个元素是谁

双向链表:每个元素只知道上一个和下一个元素

循环链表:尾节点指向头节点

性能

1)随机访问性能

        根据index找元素,时间复杂度O(n);

2)插入(删除)

        中间插入:找索引O(n)+插入O(1)=O(n)

        起始插入:插入O(1)

        结尾插入:双向O(1)

                           单向O(n)+O(1)=O(n)

单向链表

首位添加元素

语言描述

head头节点存储第一个节点的地址

1)链表为空

---头节点head=null

---定义第一个节点node=new Node(value,null)

---head头节点指向第一个节点head=node

---综合:head=new Node(value,head);

2)链表不为空

---head头节点内存储第一个节点的地址

---定义插入的节点node=new Node(value,next)

---next指向原来第一个节点的地址,所以next=head

---head节点指向插入的节点

---综合:head=new Node(value,head);

代码实现

public void addFrist(int value){
		//链表为空与链表不为空,都可写作如下
		head=new Node(value,head);
	}

尾部添加元素

语言描述

1)找到最后一个节点的地址findLast()

        1.链表为空,即head=null,返回null

        2.链表不为空

                遍历链表得到最后一个节点的地址,返回地址

2)添加元素

             1.接受findLast()的返回值,last=findLast()

             2.if last=null,调用addFirst()方法;

             3.else:添加新的节点,last.next值指向要添加的节点--last.next=new Node(value,null);

代码实现

/**
*尾部添加元素---第一步,获取最后一个节点Node的地址
*/
	public Node findLast(){
	if (head == null) {//空链表
		return null;
	}
	Node p;
	for(p=head;p.next!=null;p=p.next){}
	return p;
}
/**
 * 尾部添加元素---第二步,把元素添加到最后
 */
	public void addLast(int value){
	Node last=findLast();
	if (last==null){
		addFrist(value);
	}else{
	//添加节点
	last.next = new Node(value, null);
}}

遍历链表

语言描述

普通,函数接口,迭代器.......

代码实现

	/**
	 * 遍历链表1--普通
	 */
	public void loop1(){
		Node print=head;//定义一个指针指向头节点
		//当指针指向的地址不为null时循环
		while(print!=null){
			System.out.println(print.value);
			print = print.next;//指针指向下一个节点的地址
		}
	}

	/**
	 * 遍历2--函数接口遍历--while循环
	 */
	public void loop2(Consumer<Integer> consumer){
		Node print=head;//定义一个指针指向头节点
		//当指针指向的地址不为null时循环
		while(print!=null){
			consumer.accept(print.value);
			print = print.next;//指针指向下一个节点的地址
		}
	}
	/**
	 * 遍历3--函数接口遍历--for循环
	 */
	public void loop3(Consumer<Integer> consumer){
		Node print=head;//定义一个指针指向头节点
		//当指针指向的地址不为null时循环
		for(print=head;print!=null;print=print.next){
			consumer.accept(print.value);
		}
	}
	/**
	 * 遍历4--迭代器遍历
	 */
	@Override
	public Iterator<Integer> iterator() {
		return new Iterator<Integer>() {
			Node p=head;
			@Override
			public boolean hasNext() {
				return p!=null;
			}

			@Override
			public Integer next() {
				int i = p.value;
				p=p.next;
				return i;
			}
		};
	}

	/**
	 * 遍历方法5---递归遍历
	 */
	public void loop5(){
		recursion(head);
	}

	/**
	 * 递归遍历
	 * @param n
	 * 输入节点
	 */
	public void recursion(Node n ){
		if (n==null){
			return;
		}
		System.out.println(n.value);
		recursion(n.next);
	}

通过索引找元素

语言描述

1)通过索引找节点findNode(int index)

        1.定义计数值int i;

        2.遍历链表,当i=index时,返回节点地址,没找到就返回null;

2)通过节点返回对应值

        1.p=findNode(index);

        2.p=null--返回错误

        3.返回p.value;

代码实现

	/**
	 * 	通过链表的索引找元素--第一步:找到索引对应的节点
	 */
	public Node findNode(int index){
		int i=0;
		//遍历列表,定义计数
		for (Node p = head; p !=null ; p=p.next,i++) {
			if(i==index){
				return p;
			}
		}
		return null;
	}
	/**
	 * 	通过链表的索引找元素--第二步:返回该节点对应的值
	 */
	public int get(int index){
		Node p = findNode(index);
		if (p == null) {
			throw new IllegalArgumentException(String.format("index [%d] 越界 %n",index));
		}
		return p.value;
	}

通过索引添加元素

语言描述

代码实现

	/**
	 * 通过索引增加新元素
	 */
	public void insert(int index,int value){
		//情况1,添加的索引为0
		if (index == 0) {
			addFrist(value);
			return;//不要忘记
		}
		Node node = findNode(index - 1);//获取index前的节点
		//情况2,索引越界
		if (node==null){
			throw new IllegalArgumentException(String.format("index [%d] 越界 %n",index));
		}
		node.next=new Node(value,node.next);//定义要添加的节点信息
	}

删除链表第一个元素

语言描述

代码实现

	/**
	 * 删除链表的第一个节点
	 * 当头节点为空时,报错
	 */
	public void removeFirst(){
		if (head == null) {
			throw new IllegalArgumentException(String.format("index [0]不合法"));
		}
		head = head.next;//获取第二个节点的地址赋值给头节点
	}

删除链表指定索引元素

语言描述

代码实现

	/**
	 * <p>删除链表的指定索引的元素</p>
	 * <p>**步骤:**</p>
	 *<p>		1.获取prev节点</p>
	 *<p>		2.获取索引处节点removed</p>
	 *<p>		3.node.next获取索引后节点的地址</p>
	 *<p>		4.赋值给prev.next</p>
	 *<p>		5.java会自动清理没用的数据,所以索引处节点所占内存不用管</p>
	 *<p>**特殊**:
	 * <p>1.prev=null;2.removed=null;3.index=0-->removeFirst()</p>
	 * <p>***********不要忘记return;****************</p>
	 * */
	public  void removed(int index){
		if (index == 0) {
			removeFirst();
			return;//不要忘记结束
		}
		Node prev = findNode(index - 1);
		if (prev==null){
			throw new IllegalArgumentException(String.format("index[%d]越界",index));
		}
		Node removed=prev.next;
		if (removed==null){
			throw new IllegalArgumentException(String.format("index[%d]越界",index));

		}
		prev.next=removed.next;
	}

带哨兵的单向链表

不用搞空链表的判断了,哨兵节点内的值没有意义

p37,p38不想看了,晚安

private Node head=new Node(666,null);//头节+哨兵节点

双向链表

 自己玩吧


public class class002DoublyLinkedListSentinel implements Iterable<Integer> {//双向链表类
    Node head;
    Node tail;

    public class002DoublyLinkedListSentinel() {
        head = new Node(null, 54, null);//头节点
        tail = new Node(null, 54, null);    //尾节点
        head.next = tail;
        tail.prev = head;
    }


    //节点类
    static class Node {
        Node prev;//指向前驱
        int value;//元素
        Node next;//指向后继

        public Node(Node prev, int value, Node next) {
            this.next = next;
            this.value = value;
            this.prev = prev;
        }
    }

    /**
     * <p>添加元素至最后一位addLast</p>
     * <p>1.定义新节点</p>
     * <p>2.头尾指向新节点</p>
     */
    public void addLast(int value) {
        Node prev = tail.prev;
        Node added = new Node(prev, value, tail);//添加的节点
        prev.next = added;
        tail.prev = added;
    }

    /**
     * <p>根据索引找节点</p>
     */
    public Node findNode(int index) {
        int i = -1;//记录索引值
        for (Node p = head; p != tail; p = p.next, i++) {
            if (index == i) {
                return p;
            }
        }
        return null;
    }

    /**
     * <p>输出索引对应的值</p>
     */
    public int get(int index) {
        Node p = findNode(index);
        if (p == null) {
            throw new IllegalArgumentException(String.format("索引越界异常"));
        }
        return p.value;
    }

    /**
     * <p>根据索引位置插入值</p>
     * <p>1.创建新节点added</p>
     * <p>2.获取索引前节点prev</p>
     * <p>3.获取索引处节点next=prev.next</p>
     * <p>4.added添加到prev和next中间</p>
     * <p>***特殊***</p>
     * <p>1.prev=null--返回异常</p>
     */
    public void addNode(int index, int value) {
        Node prev = findNode(index - 1);
        if (prev == null) {
            throw new IllegalArgumentException(String.format("索引越界异常"));
        }
        Node next = prev.next;
        if (next == tail) {
            addLast(value);
            return;
        }
        Node added = new Node(prev, value, next);
        prev.next = added;
        next.prev = added;
    }

    /**
     * <p>迭代器遍历双向链表</p>
     */
    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            Node p = head.next;

            @Override
            public boolean hasNext() {
                return p != tail;
            }

            @Override
            public Integer next() {
                int value = p.value;
                p = p.next;
                return value;
            }
        };
    }
    /**
     * <p>按索引删除元素</p>
     * <p>1.得到节点prve,removed(索引处节点),next(索引后节点)</p>
     * <p>2.prve.next=next;next.prve=prve</p>
     * <p>****特殊****</p>
     * <p>1.该索引在链表内不存在,即prve=null,返回异常</p>
     * <p>2.删除的元素为尾节点,即removed=tail,返回异常</p>
     */
    public void removed(int index) {
        Node prve = findNode(index - 1);
        if (prve == null) {
            throw new IllegalArgumentException(String.format("索引越界异常"));
        }
        Node removed = prve.next;
        if (removed == tail) {
            throw new IllegalArgumentException(String.format("索引越界异常"));
        }
        Node next = removed.next;
        prve.next = next;
        next.prev = prve;
    }
    /**
     * <p>删除第一个元素</p>
     * <p>调用removed()方法传入实参’0‘</p>
     */
    public  void removeFirst(){
            removed(0);
        }
    /**
     * <p>删除最后一个元素</p>
     * <p>获取尾节点tail</p>
     * <p>获取最后一个节点last=tail.prve</p>
     * <p>获取last前驱节点prve=last.prve</p>
     * <p>这样那样:prve.next=tail,tail.prve=prve</p>
     * <p>********特殊*******</p>
     * <p>1.列表内没有元素,只有头尾节点,即tail.prve=head</p>
     */
    public void removeLast(){
        Node last = tail.prev;
        if (last == head) {
            throw new IllegalArgumentException(String.format("sorry,索引越界惹"));
        }
        Node prev = last.prev;
        prev.next=tail;
        tail.prev=prev;
    }
}

循环链表

 循环列表定义

双向循环列表带哨兵,哨兵即作头也作尾

代码实现

public class class003 {
static class Node{
    Node prve;
    int value;
    Node next;
    public Node(Node prve, int value, Node next){
        this.next=next;
        this.value=value;
        this.prve=prve;
    }
}
    private Node sentinel=new Node(null,56,null);
public class003(){
    this.sentinel.prve=sentinel;
    this.sentinel.next=sentinel;
}
}

首位添加元素addFirst

语言描述

----------1.定义添加的节点added;

----------2.得到哨兵节点和next节点

----------3.added节点插入

代码实现

 public void addFirst(int value) {
        Node next = sentinel.next;
        Node added = new Node(sentinel, value, next);
        sentinel.next = added;
        next.prve = added;
    }

遍历元素

语言描述:

迭代器遍历哦~!!~~~~~~

代码实现

public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            Node p=sentinel.next;

            @Override
            public boolean hasNext() {
                return p!=sentinel;
            }

            @Override
            public Integer next() {
                int value=p.value;
                p=p.next;
                return value;
            }
        };
    }

末尾添加元素addLast

语言描述

--1.创建添加的节点

--2.哨兵节点和当前最后一个节点prve=sentinal.next;

--3.added节点插入

代码实现

    public  void addLast(int value){
        Node prve = sentinel.prve;
        Node added = new Node(prve, value, sentinel);
        prve.next=added;
        sentinel.prve=added;
    }

删除第一个节点

语言描述

--1.待删除的元素removed;

--2.哨兵节点,及removed的下一个元素next=removed.next;

--3.removed节点删除;

--4.特殊:链表内只剩哨兵节点,返回异常;

代码实现 

 public void removeFirst() {
        Node removed = sentinel.next;
        if (removed == sentinel) {
            throw new IllegalArgumentException(String.format("只剩哨兵节点了,不可再删"));
        }
        Node next = removed.next;
        sentinel.next=next;
        next.prve=sentinel;
    }

删除最后一个节点

语言描述

--1.待删除的节点removed=sen.prve;

--2.removed前的节点prve=removed.prve;

--3.删除removed,sen指向prve;

代码实现

 public void removeLast(){
        Node removed = sentinel.prve;
        if (removed == sentinel) {
            throw new IllegalArgumentException(String.format("只剩哨兵节点了,不可再删"));
        }
        Node prve = removed.prve;
        sentinel.prve=prve;
        prve.next=sentinel;

    }

根据值删除链表节点

语言描述

---1.先得到值对应的节点findValue()

        1)遍历链表

         2)找到对应节点返回p

--2.删除对应节点removed()

        1)接受返回的p

        2)if p=null,返回return;

        3)得到p节点的前驱,后继节点

        4)删除p节点

代码实现

public Node findValue(int value){
        Node p=sentinel.next;
        while (p!=sentinel){
            if (p.value==value){
                return p;
            }
            p=p.next;
        }
        return null;
    }

  
    public void removed(int value){
        Node p = findValue(value);
        if (p==null){
            return;
        }
        Node prve = p.prve;
        Node next = p.next;
        prve.next=next;
        next.prve=prve;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值