链表与线性数据结构
链表:
-
最简单的动态数据结构
-
更深入的理解引用(或指针)
-
更深入的理解递归
-
辅助组成其他数据结构
优点:真正的动态,不需要处理固定容量的问题
缺点:丧失了自由访问的能力
数组和链表的对比
链表的头:head 指向第一个节点
package com.dataStructrue;
public class LinkedList <E>{
private class Node{
public E e;
public Node next;
public Node(E e,Node next){
this.e=e;
this.next=next;
}
public Node(E e){
this(e,null);
}
public Node(){
this(null,null);
}
@Override
public String toString(){
return e.toString();
}
}
private Node head;
private int size;
public LinkedList(){
head=null;
size=0;
}
//获取链表中元素个数
public int getSize(){
return size;
}
//
public boolean isEmpty(){
return size==0;
}
//链表头添加新的元素e
public void addFirst(E e){
// Node node=new Node(e);
// node.next=head;
// head=node;
head=new Node(e,head);
size++;
}
//链表中间第index(0-based)个位置添加新的元素e
//在实际中不常用这个操作,做练习题用
public void add(int index,E e){
if (index<0||index>size)
throw new IllegalArgumentException("位置异常");
if (index==0)
addFirst(e);
else {
Node prev=head;
for (int i = 0; i < index - 1; i++) {
prev=prev.next;
}
// Node node=new Node(e);
// node.next=prev.next;
// prev.next=node;
prev.next=new Node(e,prev);
size++;
}
}
//在链表末尾添加新的元素e
public void addLast(E e){
add(size,e);
}
}
为链表设立虚拟头节点
package com.dataStructrue;
public class LinkedList <E>{
private class Node{
public E e;
public Node next;
public Node(E e,Node next){
this.e=e;
this.next=next;
}
public Node(E e){
this(e,null);
}
public Node(){
this(null,null);
}
@Override
public String toString(){
return e.toString();
}
}
private Node dummyHead;
private int size;
public LinkedList(){
dummyHead=new Node(null,null);
size=0;
}
//获取链表中元素个数
public int getSize(){
return size;
}
//
public boolean isEmpty(){
return size==0;
}
//链表中间第index(0-based)个位置添加新的元素e
public void add(int index,E e){
if (index<0||index>size)
throw new IllegalArgumentException("位置异常");
Node prev=dummyHead;
for (int i = 0; i < index; i++) {
prev=prev.next;
}
prev.next=new Node(e,prev);
size++;
}
//链表头添加新的元素e
public void addFirst(E e){
add(0,e);
}
//在链表末尾添加新的元素e
public void addLast(E e){
add(size,e);
}
}
从链表中删除元素
调用toString时,由于定义了虚拟头部,导致e值为null,无法输出
错误示范
package com.dataStructrue;
public class LinkedList <E>{
private class Node{
public E e;
public Node next;
public Node(E e,Node next){
this.e=e;
this.next=next;
}
public Node(E e){
this(e,null);
}
public Node(){
this(null,null);
}
@Override
public String toString(){
return e.toString();
}
}
private Node dummyHead;
private int size;
public LinkedList(){
dummyHead=new Node(null,null);
size=0;
}
//获取链表中元素个数
public int getSize(){
return size;
}
//
public boolean isEmpty(){
return size==0;
}
//链表中间第index(0-based)个位置添加新的元素e
public void add(int index,E e){
if (index<0||index>size)
throw new IllegalArgumentException("位置异常");
Node prev=dummyHead;
for (int i = 0; i < index; i++) {
prev=prev.next;
}
prev.next=new Node(e,prev);
size++;
}
//链表头添加新的元素e
public void addFirst(E e){
add(0,e);
}
//在链表末尾添加新的元素e
public void addLast(E e){
add(size,e);
}
//获得链表中第index个位置元素
//练习用
public E get(int index){
if(index<0||index>=size)
throw new IllegalArgumentException("位置异常");
Node cur=dummyHead.next;
for (int i = 0; i < index; i++) {
cur=cur.next;
}
return cur.e;
}
//获得链表的第一个元素
public E getFirst(int index){
return get(0);
}
//获得链表的最后一个元素
public E getLast(int index){
return get(size-1);
}
//修改第index位置元素为e
public void set(int index,E e){
if(index<0||index>=size)
throw new IllegalArgumentException("位置异常");
Node cur=dummyHead.next;
for (int i = 0; i < index; i++) {
cur=cur.next;
}
cur.e=e;
}
//查找链表中是否存在元素e
public boolean contains(E e){
Node cur=dummyHead.next;
while (cur!=null){
if (cur.e.equals(e))
return true;
cur=cur.next;
}
return false;
}
@Override
public String toString(){
StringBuilder res=new StringBuilder();
// Node cur=dummyHead.next;
// while (cur!=null){
// res.append(cur+"->");
// cur=cur.next;
// }
for(Node cur=dummyHead.next;cur!=null;cur=cur.next)
res.append(cur+"->");
res.append("NULL");
return res.toString()+"";
}
}
package com.dataStructrue;
public class M {
public static void main(String[] args){
LinkedList<Integer>linkedList=new LinkedList<>();
for (int i = 0; i < 5; i++) {
linkedList.addFirst(i);
System.out.println(linkedList);
}
linkedList.add(2,666);
System.out.println(linkedList);
}
}
预计输出结果:
实际输出结果:
由于25行toString中出现空指针而报错。
add方法里面,prev.next=new Node(e,prev.next);
漏掉了.next, prev.next=new Node(e,prev);导致进入了无限套娃
时间复杂度分析
增、删、改、查的时间复杂度都是O(n)
此时与数组一样,但是由于是动态的,所以不会浪费大量内存
使用链表实现栈
package com.dataStructrue;
public class LinkedList <E>{
private class Node{
public E e;
public Node next;
public Node(E e,Node next){
this.e=e;
this.next=next;
}
public Node(E e){
this(e,null);
}
public Node(){
this(null,null);
}
@Override
public String toString()throws IllegalArgumentException{
if(e==null)
throw new IllegalArgumentException("KONG");
return e.toString();
}
}
private Node dummyHead;
private int size;
public LinkedList(){
dummyHead=new Node(null,null);
size=0;
}
//获取链表中元素个数
public int getSize(){
return size;
}
//
public boolean isEmpty(){
return size==0;
}
//链表中间第index(0-based)个位置添加新的元素e
public void add(int index,E e){
if (index<0||index>size)
throw new IllegalArgumentException("位置异常");
Node prev=dummyHead;
for (int i = 0; i < index; i++) {
prev=prev.next;
}
prev.next=new Node(e,prev.next);
size++;
}
//链表头添加新的元素e
public void addFirst(E e){
add(0,e);
}
//在链表末尾添加新的元素e
public void addLast(E e){
add(size,e);
}
//获得链表中第index个位置元素
//练习用
public E get(int index){
if(index<0||index>=size)
throw new IllegalArgumentException("位置异常");
Node cur=dummyHead.next;
for (int i = 0; i < index; i++) {
cur=cur.next;
}
return cur.e;
}
//获得链表的第一个元素
public E getFirst(){
return get(0);
}
//获得链表的最后一个元素
public E getLast(int index){
return get(size-1);
}
//修改第index位置元素为e
public void set(int index,E e){
if(index<0||index>=size)
throw new IllegalArgumentException("位置异常");
Node cur=dummyHead.next;
for (int i = 0; i < index; i++) {
cur=cur.next;
}
cur.e=e;
}
//查找链表中是否存在元素e
public boolean contains(E e){
Node cur=dummyHead.next;
while (cur!=null){
if (cur.e.equals(e))
return true;
cur=cur.next;
}
return false;
}
@Override
public String toString(){
StringBuilder res=new StringBuilder();
// Node cur=dummyHead.next;
// while (cur!=null){
// res.append(cur+"->");
// cur=cur.next;
// }
for(Node cur=dummyHead.next;cur!=null;cur=cur.next)
res.append(cur+"->");
res.append("NULL");
return res.toString();
}
//从链表中删除index位置的元素
public E remove(int index){
if(index<0||index>=size)
throw new IllegalArgumentException("位置异常");
Node prev=dummyHead;
for (int i = 0; i < index; i++) {
prev=prev.next;
}
Node retNode=prev.next;
prev.next=retNode.next;
retNode.next=null;
size--;
return retNode.e;
}
//从链表中删除最后一个元素,返回删除的元素
public E removeLast(){
return remove(size-1);
}
public E removeFirst(){
return remove(0);
}
}
package com.dataStructrue;
import javax.annotation.Resource;
public class LinkedListStack<E> implements Stack<E>{
// private LinkedList<E> list;
//
// public LinkedListStack(){
// list=new LinkedList<>();
// }
private LinkedList<E> list=new LinkedList<E>();
@Override
public int getSize(){
return list.getSize();
}
@Override
public boolean isEmpty(){
return list.isEmpty();
}
@Override
public void push(E e){
list.addFirst(e);
}
@Override
public E peak(){ return list.getFirst(); }
@Override
public E pop(){
return list.removeFirst();
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append("Stack:top");
res.append(list);
return res.toString();
}
public static void main(String[] args){
LinkedListStack<Integer>stack=new LinkedListStack<>();
for (int i = 0; i < 5; i++) {
stack.push(i);
System.out.println(stack);;
}
stack.pop();
System.out.println(stack);
}
}
使用链表实现队列
由于没有dummyHead,需要注意链表为空的问题
package com.dataStructrue;
public class LinkedListQueue<E> implements Queue<E> {
private class Node{
public E e;
public Node next;
public Node(E e, Node next){
this.e=e;
this.next=next;
}
public Node(E e){
this(e,null);
}
public Node(){
this(null,null);
}
@Override
public String toString(){
return e.toString();
}
}
private Node head,tail;//定义头节点和尾节点
private int size;//定义整型记录长度
public LinkedListQueue(){//与不写构造函数,默认的构造函数是一样的
head=null;
tail=null;
size=0;
}
@Override
public int getSize(){
return size;
}
@Override
public boolean isEmpty(){
return size==0;
}
@Override//入队操作
public void enqueue(E e){
if(tail==null){
tail=new Node(e);
head=tail;
}else {
tail.next=new Node(e);
tail=tail.next;
}
size++;
}
@Override//出队操作
public E dequeue(){
if (isEmpty())
throw new IllegalArgumentException("不能出空");
Node retNode=head;
head=head.next;
retNode.next=null;
if (head==null)
tail=null;//链表只有一个元素时,首尾是一样的
size--;
return retNode.e;
}
@Override
public E getFront(){
if (isEmpty())
throw new IllegalArgumentException("不能为空");
return head.e;
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append("Queue:front");
Node cur=head;
while (cur!=null){
res.append(cur+"->");
cur=cur.next;
}
res.append("NULL tail");
return res.toString();
}
public static void main(String[] args) {
LinkedListQueue<Integer>queue=new LinkedListQueue<>();
for (int i = 0; i < 10; i++) {
queue.enqueue(i);
System.out.println(queue);
if (i%3==2){
queue.dequeue();
System.out.println(queue);
}
}
}
}
/*结果
Stack:top0->NULL
Stack:top1->0->NULL
Stack:top2->1->0->NULL
Stack:top3->2->1->0->NULL
Stack:top4->3->2->1->0->NULL
Stack:top3->2->1->0->NULL
*/