链式表
概念:每一个元素都包含一个称之为结点(node)的结构,我们去添加一个元素就会产生一个包含
元素的结点,每个节点和它相邻的节点相连接
结点=数据域+引用域
节点之间是通过引用域相连接的
链表是一种物理存储单元上非连续的存储结构,数据之间也是非连续的,数据元素的顺序是通过链表中的引用域链接次序决定的
实现
class Node{}
带头结点的链表,永远有一head引用指向当前链表的第一个节点,同时该链表的第一个节点
不能存放有效元素,data域只能存放一个无效元素
实现带头结点单链表
class SingleLinkedListTakeHead<T>{
private Node<T> head;
class Node<T>{
private T data;
private Node<T> next;
public Node(T data){
this.data = data;
}
}
public SingleLinkedListTakeHead(){
head = new Node<T>((T)new Object());
}
public void addHead(T data){
Node<T> newNode = new Node<>(data);
//将head后面的节点绑定在newNode节点之后
newNode.next = head.next;
//将head节点的next指向newNode
head.next = newNode;
}
public void addTail(T data){
Node<T> newNode = new Node<>(data);
//遍历当前链表,找到尾节点,尾节点之后绑定newNode
Node<T> tmp = head;
while(tmp.next != null){
tmp = tmp.next;
}
//跳出循环tmp.next = null,此时tmp就是尾节点
tmp.next = newNode;
}
public boolean delete(T data){
if(head.next == null){
return false;
}
//删除节点,涉及到删除节点的前一个节点的操作
Node<T> tmp = head;
while(tmp.next != null ){
if(tmp.next.data == data){
//tmp为所删除节点的前一个节点
tmp.next = tmp.next.next;
//连续使用.操作符,注意.操作符之前的引用是否为null
//如果为null,会造成空指针异常
return true;
}
tmp = tmp.next;
}
return false;
}
public T findNode(int index){
//假设当前链表的index从0开始
if(index <= 0) return null;
Node<T> tmp = head.next;
while(index-- > 1 && tmp != null){
tmp = tmp.next;
}
if(tmp != null){
return tmp.data;
}
return null;
}
public boolean set(int index, T newData){
if(index <= 0 ) return false;
Node<T> tmp = head.next;
while(index-- > 1 && tmp != null){
tmp = tmp.next;
}
if(tmp != null){
tmp.data = newData;
return true;
}
return false;
}
public String toString(){
StringBuilder sb = new StringBuilder();
if(head.next == null){
return "No Data";
}
//遍历链表
Node<T> tmp = head.next;
while(tmp != null){
sb.append(tmp.data + " ");
tmp = tmp.next;
}
return sb.toString();
}
}
public class TestDemo1 {
public static void main(String[] args) {
SingleLinkedListTakeHead<Integer> list = new SingleLinkedListTakeHead<>();
list.addHead(1);
list.addHead(2);
list.addHead(3);
list.addHead(4);
list.addHead(5);
System.out.println(list.toString());
list.delete(3);
list.delete(1);
System.out.println(list.toString());
System.out.println(list.findNode(2));
System.out.println(list.set(2, 100));
System.out.println(list.toString());
list.addTail(1000);
list.addTail(2000);
System.out.println(list.toString());
}
}
实现不带头节点的单链表
class SingleLinkedList<T>{
protected Node<T> head;
class Node<T>{
protected T data;
protected Node<T> next;
public Node(T data){
this.data = data;
}
}
public void add(T data){
Node<T> newNode = new Node<>(data);
//第一种情况,head节点为空,直接head指向newNode
if(head == null){
head = newNode;
}else{
//第二种情况,head节点非空,遍历整个链表,找到尾节点,添加新节点
Node<T> tmp = head;
while(tmp.next != null){
tmp = tmp.next;
}
//tmp即为当前链表的尾节点,在tmp之后绑定newNode
tmp.next = newNode;
}
}
public boolean delete(T data){
//删除节点会涉及到所删除节点的前一个节点的操作,head节点没有前一节点
//需要单独处理
//第一种情况,删除头节点,直接将head设置为下一个节点
if(head.data == data){
head = head.next;
return true;
}else{
//第二种情况,不是头节点,需要遍历找到所删除节点
Node<T> tmp = head;
while(tmp.next != null){
if(tmp.next.data == data){
tmp.next = tmp.next.next;
return true;
}
tmp = tmp.next;
}
return false;
}
}
public String toString(){
StringBuilder sb = new StringBuilder();
if(head == null){
return "No Data";
}
Node<T> tmp = head;
sb.append(tmp.data + " ");
while(tmp.next != null){
sb.append(tmp.next.data + " ");
tmp = tmp.next;
}
return sb.toString();
}
}
public class TestDemo2 {
public static void main(String[] args) {
SingleLinkedList<String> list = new SingleLinkedList<>();
list.add("tu");
list.add("lun");
list.add("you");
list.add("xiu");
list.add("123");
System.out.println(list.toString());
list.delete("tu");
list.delete("123");
list.delete("you");
System.out.println(list.toString());
}
}
单向循环链表
class LoopSingleLinkedList<E>{
protected Node<E> head;
class Node<E>{
protected E data;
protected Node<E> next;
public Node(E data){
this.data = data;
}
}
public void add(E data){
//创建一个新节点
Node<E> newNode = new Node<>(data);
//当前链表为空
if(head == null){
head = newNode;
newNode.next = head;
}
//遍历至尾节点
Node<E> tmp =head;
while(tmp.next != head){
tmp = tmp.next;
}
newNode.next = tmp.next;
tmp.next = newNode;
}
public boolean delete(E data){
//head是所删除节点,改变head的引用,同时改变尾节点的next
if(head.data == data){
//找到尾节点
Node<E> tmp = head;
while(tmp.next != head){
tmp = tmp.next;
}
head = head.next;
tmp.next = head;
return true;
}
Node<E> prev = head;//保存当前节点的前一个节点
Node<E> cur = head.next;//保存当前节点
while(cur != head){
if(cur.data == data){
prev.next = cur.next;
return true;
}
prev = cur;
cur = cur.next;
}
return false;
}
public int getLength(){
int count = 1; //计数器
Node<E> tmp = head.next;
while(tmp != head){
count++;
tmp = tmp.next;
}
return count;
}
public E findValue(int index){
//index默认从0开始,head的索引就是0
int length = getLength();
//判断index的合法性
if(index < 0 || index >= length){
return null;
}
Node<E> tmp = head;
for(int i=0; i<index; i++){
tmp = tmp.next;
}
//跳出循环 i = index, tmp指向就是所要查找的节点
return tmp.data;
}
public void show(){
System.out.print(head.data + " ");
Node<E> tmp = head.next;
while(tmp != head){
System.out.print(tmp.data + " ");
tmp = tmp.next;
}
System.out.println();
}
}
public class TestDemo1 {
public static void main(String[] args) {
LoopSingleLinkedList<Integer> list = new LoopSingleLinkedList<>();
list.add(10);
list.add(20);
list.add(0);
list.add(1);
list.add(5);
list.add(15);
list.add(30);
list.show();
list.delete(10);
list.delete(30);
list.delete(0);
list.show();
System.out.println(list.findValue(0));
System.out.println(list.findValue(3));
}
}
双向链表
class DoubleLinkedList<E>{
protected Node<E> first; //指向链表中第一个节点
protected Node<E> last; //指向链表中的最后一个节点
protected int size; //当前链表的节点个数
class Node<E>{
protected E data; //当前节点的内容
protected Node<E> prev; //前驱引用
protected Node<E> next; //后继引用
public Node(E data, Node<E> prev, Node<E> next){
this.data = data;
this.prev = prev;
this.next = next;
}
}
public void add(E value){
Node<E> tmp = last;
Node<E> newNode = new Node<>(value, tmp, null);
last = newNode;
if(tmp == null){
first = newNode; //原先链表为空,此时该节点作为链表中第一个节点存在
}else{
tmp.next = newNode;
}
size++;
}
public void add(int index, E value){
//根据index找到该节点
if(index < 0 || index > size){
return;
}
if(index == size){
add(value);
}else{
//根据index得到该位置的节点
Node<E> succ = findNodeByIndex(index);
//得到该节点的前驱引用
Node<E> succPre = succ.prev;
//new一个新节点
Node<E> newNode = new Node(value, succPre, succ);
//绑定新节点为succ的前驱引用
succ.prev = newNode;
if(succPre == null){
//说明原先链表只有一个节点
first = newNode;
}else{
succPre.next = newNode;
}
}
size++;
}
public Node<E> findNodeByIndex(int index){
Node<E> tmp = first;
for(int i=0; i<index; i++){
tmp = tmp.next;
}
return tmp;
}
public Node<E> findValueByValue(E value){
for(Node<E> tmp = first; tmp != null; tmp = tmp.next){
if(value.equals(tmp.data)){
return tmp;
}
}
return null;
}
public boolean delete(E value){
//删除元素所在的节点
//找出元素所在的节点
Node<E> succ = findValueByValue(value);
if(succ == null){
return false;
}
//考虑删除的是第一个节点或者最后一个节点的情况
Node<E> succPrev = succ.prev;
Node<E> succNext = succ.next;
//如果删除的是第一个节点
if(succPrev == null){
first = succNext;
}else{
succPrev.next = succNext;
succ.prev = null;
}
//如果删除的是最后一个节点
if(succNext == null){
last = succPrev;
}else{
succNext.prev = succPrev;
succ.next = null;
}
size--;
return true;
}
public String toString(){
StringBuilder sb = new StringBuilder();
for(Node<E> tmp = first; tmp != null; tmp = tmp.next){
sb.append(tmp.data + " ");
}
return sb.toString();
}
}
public class TestDemo3 {
public static void main(String[] args) {
DoubleLinkedList<String> list = new DoubleLinkedList<>();
list.add("abc");
list.add("faafabc");
list.add("fafabc");
list.add("vsdfabc");
list.add("wwabc");
list.add("adaabc");
System.out.println(list.toString());
list.add(1, "tulun");
list.add(5, "software");
System.out.println(list.toString());
list.delete("abc");
list.delete("adaabc");
list.delete("fafabc");
System.out.println(list.toString());
}
}