1.链表
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
2.链表的特点
优点
- 动态分配内存。链表不需要预先分配固定空间,可以根据需要动态地分配和释放内存,这使得链表在处理大小可变的数据集合时非常灵活。
- 插入和删除操作高效。在链表中插入或删除元素时,只需要更新受影响节点的链接指针,而不需要移动其他元素,这与需要在插入或删除元素后重新排列元素的数组相比,效率更高。
- 灵活度高。链表的大小可以根据需要自动扩展或缩小,这使得链表在处理动态变化的数据集合时非常方便。
- 空间分散。链表中的元素可以在内存中的任何位置,不需要连续存储,这有助于提高内存利用率并减少内存碎片。
链表的这些优点使得它成为处理动态数据集合和频繁进行插入或删除操作的理想选择。
缺点
- 存储空间需求较大。链表中的每个节点除了存储数据外,还需要额外的存储空间来存储指针,这导致链表相对于数组结构在空间开销上更大。
- 访问效率较低。链表不支持随机访问,访问链表中某个特定元素需要从头节点开始,顺序遍历节点直到找到所需元素,这使得链表在查找操作上的效率较低。
- 内存碎片问题。由于链表的节点在内存中可能非连续分布,这可能导致内存碎片问题,从而影响内存管理的效率。
3.链表的种类
链表的种类有很多,常见的有单向链表,双向链表,循环链表等,某些链表为了对头元素操作方便还在第一个元素前添加了一个哨兵(sentinel)节点
4.用Java实现单向链表
单向链表
public class SingleLinkedList implements Iterable{
/**
* 链表是数据的线性集合,但在存储中地址并不连续,每个元素都指向下一个元素
* 分类:单向链表,双向链表,循环链表
* 特点:增删快,查找慢
*/
private Node head = null;//初始值为null
//节点类
private static class Node{
int value;//值
Node next;//下一个节点指针
//提供有参构造器
public Node(int value,Node next){
this.value = value;
this.next = next;
}
}
//向头部位置添加元素
public void addhead(int value){
//当前链表为空(可省略,第二句可处理该情况,head初始值为null)
//head = new Node(value,null);
//当前链表不为空
/*Node newnode = new Node(value,head);
head = newnode;*/
head = new Node(value,head);
}
//向尾部添加元素
public void addlast(int value){
//先遍历找到最后一个位置
Node p = head;
while (p.next != null){
p = p.next;
}
p.next = new Node(value,null);//遍历到了最后一个元素
}
//向指定索引位置添加元素
//遍历
public void print(){
Node p = head;
while (p != null){
System.out.println(p.value);
p = p.next;//更新指针p,指向下一节点
}
}
//函数式遍历方法foreach
public void foreach(Consumer<Integer> consumer){
Node p = head;
while (p != null){
consumer.accept(p.value);
p = p.next;//更新指针p,指向下一节点
}
}
//迭代器遍历
@Override
public Iterator<Integer> iterator() {
//匿名内部类
return new Iterator<Integer>() {
Node p = head;
@Override
public boolean hasNext() {
return p != null;//遍历到null结束
}
@Override
public Integer next() {
int i = p.value;
p = p.next;
return i;
}
};
}
//获取index的元素
public Integer getvaluebyindex(int index){
int i = 0;
Node p = head;
if(index == 0){
return p.value;
}
while (p != null){
p = p.next;
i++;
if(i == index){
break;
}
}
return p.value;
}
}