一、动态链表
为了表示每个数据元素ai 与其直接后继数据元素ai+1之间的逻辑关系,对
数据元素a1来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息
(直接后的存储位置),我们把 存储 数据元素 信息的域称为数据域,把存储直接后
继位置的称为指针域。针域中存储的信息称做指针或链。这两部分信息组成数据
元素 ai 的存储映像,称为结点(Node)。
n个结点(ai 的存储映像)链结成一个链表,即为线性表(a1,a2,...,an)的链
式存储结构,因为此链表的每个结点中只包一个指针域,所以叫单链表
数据域 data | 指针域 next |
二、头结点VS头指针
头结是指 链表中的第一个结,有真实节点 和 虚拟头节点 之分
真实头节点:其第一个节点用于存储数据(我们这里采用真实头节点)
虚拟头节点:其第一个节点不允许存储数据
头指针:仅仅是一个引用变量,存储头节点地址的指针而已
尾指针:同头指针,不过是链表中最后一个节点的指针而已
三、单向链表 LinkedSinglyList
LinkedSinglyList就是线性结构链式存储方式的具体实现,称为单链表
四、代码实现
package p3.链式结构;
import p1.接口.List;
import java.util.Comparator;
import java.util.Iterator;
//单向链表
public class LinkedSinglyList<E> implements List<E> {
//定义一个内部类
//外部类是链表,内部类是结点
private class Node {
E data;//数据域
Node next;//指针域
public Node() {
this(null, null);
}
public Node(E data) {
this(data, null);
}
public Node(E data, Node next) {
this.data = data;
this.next = next;
}
@Override
public String toString() {
return data.toString();
}
}
private Node head;//头指针
private Node tail;//尾指针
private int size;//元素的个数
public LinkedSinglyList() {
head = null;
tail = null;
size = 0;
}
public LinkedSinglyList(E[] arr) {
if (arr == null || arr.length == 0) {
throw new IllegalArgumentException("arr is null");
}
for (int i = 0; i < arr.length; i++) {
add(arr[i]);
}
}
@Override
public void add(E element) {
add(size, element);
}
@Override
public void add(int index, E element) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("add index out of range");
}
Node n = new Node(element);
if(size==0){
head=n;
tail=n;
}else if(index==0){//往头部添加,当前指针指向头指针 头指针指向当前指针
n.next=head;
head=n;
}else if(index==size){//往尾部添加,当尾指针指向当前指针 尾指针指向当前指针
tail.next=n;
tail=n;
}else {//往中间某个位置添加 当前指针指向-1位置的指针(此时当前指针指向了下一个) -1位置的指针指向当前
Node p=head;
for (int i=0;i<index-1;i++){//将指针移到-1的位置
p=p.next;
}
n.next=p.next;
p.next=n;
}
size++;
}
@Override
public void remove(E element) {
int index=indexof(element);
if(index!=-1){
remove(index);
}
}
@Override
public E remove(int index) {
if(index<0 || index>=size){
throw new IllegalArgumentException("remove index out of range");
}
E ret=null;
if(size==1){//一个元素 先保存值 再将head tail置空
ret= head.data;
head=null;
tail=null;
}else if(index==0){//头部 保存值 移head 置空
Node n=head;
ret=n.data;
head=n.next;
n.next=null;
}else if(index==size-1){//尾部 从头开始找,移动指针p到tail-1 先保存 tail-1位置置空 tail移到p
Node p=head;
while (p.next!=tail){
p= p.next;
}
ret=tail.data;
p.next=null;
tail=p;
}else {//中间移除 p移到-1的位置 -1下一个就是当前 将当前的next给-1 保存 则-1指向了下下个 再将当前.next置空
Node p=head;
for (int i=0;i<index-1;i++){
p=p.next;
}
Node n=p.next;
ret=n.data;
p.next=n.next;
n.next=null;
}
size--;
return ret;
}
@Override
public E get(int index) {
if(index<0 || index>=size){
throw new IllegalArgumentException("get index out of range");
}
if(index==0){//头 直接返回头指针的值
return head.data;
}else if(index==size-1){//尾 直接返回尾指针的值
return tail.data;
}else {//中间 定义一个指针 移到index的位置 (假设是2位置 i=0,i<2 则i取0,1移动两次 0-1-2 刚好到2位置 值为当前指针的data)
Node p=head;
for (int i=0;i<index;i++){
p=p.next;
}
return p.data;
}
}
@Override
public E set(int index, E element) {
if(index<0 || index>=size){
throw new IllegalArgumentException("set index out of range");
}
E ret=null;
if(index==0){//头 返回头指针的值,设置头指针的值为当前element
ret= head.data;
tail.data=element;
}else if(index==size-1){//尾 返回尾指针的值,设置尾指针的值为当前element
ret= tail.data;
tail.data=element;
}else {//中间 定义一个指针 移到index的位置 (假设是2位置 i=0,i<2 则i取0,1移动两次 0-1-2 刚好到2位置 值为当前指针的data)
Node p=head;
for (int i=0;i<index;i++){
p=p.next;
}
ret=p.data;
p.data=element;
}
return ret;
}
@Override
public int size() {
return size;
}
@Override
public int indexof(E element) {//设置指针从head开始, 只要指针的值不等于elemnt 后移,如果p==null说明没找到,返回-1 找到直接返回index即可(index=0 index++ )
Node p=head;
int index=0;
while (!p.data.equals(element)){
p=p.next;
index++;
if(p==null){
return -1;
}
}
return index;
}
@Override
public boolean contains(E element) {
return indexof(element)!=-1;//找完返回的值!=-1,就找到了,也就是包含
}
@Override
public boolean isEmpty() {
return size==0 && head==null && tail==null;
}
@Override
public void clear() {
head=null;
tail=null;
size=0;
}
@Override
public void sort(Comparator<E> c) {
if(c==null){
throw new IllegalArgumentException("comparator can not be null");
}
//此处为插入排序O(n^3) 同ArrayList 可用,但是时间复杂度太高(里面包含了往回找) 改进顺着找,时间复杂度就会低
/*
for (int i = 1; i < size; i++) {
E e = get(i)
int j = 0;
for (j = i; j > 0 && c.compare(get(j-1), e) > 0; j--) {
set(j,get(j-1));
}
set(j,e);
}
*/
//选择排序
if(size==0 || size==1){//一个元素或没有元素 不比较
return;
}
Node nodeA=head;
Node nodeB=nodeA.next;
while (true){
while (true){
if(c.compare(nodeA.data,nodeB.data)>0){
swap(nodeA,nodeB);//交换位置
}
if(nodeB==tail){
break;//B到了尾部,跳出内层循环
}
nodeB=nodeB.next;//指针后移,继续内层比较
}
if(nodeA==null){
break;//A为null,直接跳出外层循环,比较结束
}
nodeA=nodeA.next;//A后移,B移到A的后面
nodeB=nodeA.next;
}
}
private void swap(Node nodeA, Node nodeB) {
E temp=nodeA.data;
nodeA.data=nodeB.data;
nodeB.data=temp;
}
@Override
public List<E> sublist(int fromIndex, int toIndex) {
if(fromIndex<0 || toIndex>=size || fromIndex>toIndex){
throw new IllegalArgumentException("must 0<=fromIndex<=toIndex<=size-1");
}
LinkedSinglyList<E> list=new LinkedSinglyList<>();
/*for (int i = fromIndex; i < toIndex; i++) {//O(M)
list.add(get(i));//O(N) O(MN)~O(N^2)时间复杂度高
}*/
Node nodeA=head;
for (int i=0;i<fromIndex;i++){
nodeA=nodeA.next;//移到fromIndex
}
Node nodeB=head;
for (int i=0;i<toIndex;i++){
nodeB=nodeB.next;//移到toIndex
}
Node p=nodeA;
while (true){
list.add(p.data);
if(p==nodeB){
break;
}
p=p.next;
}
return list;
}
@Override
public String toString() {
StringBuilder sb=new StringBuilder();
sb.append('[');
if (isEmpty()) {
sb.append(']');
} else {
Node p=head;
while (true){
sb.append(p.data);
if (p==tail) {
sb.append(']');
break;
} else {
sb.append(',');
sb.append(' ');
p=p.next;
}
}
}
return sb.toString();
}
@Override
public Iterator<E> iterator() {
return new LinkedSinglyListIterator();
}
private class LinkedSinglyListIterator implements Iterator<E> {
private Node cur=head;
@Override
public boolean hasNext() {
return cur!=null;
}
@Override
public E next() {
E ret= cur.data;
cur=cur.next;
return ret;
}
}
}