概述
定义:元素储存上并不连续
分类
单向链表:每个元素只知道下一个元素是谁
双向链表:每个元素只知道上一个和下一个元素
循环链表:尾节点指向头节点
性能
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;
}