链表
链表是一种常见的基础数据结构,是一种线性表,但是链表不会按线性的顺序存储数据,而是在每个节点里存到下一个节点的指针。
优点:
使用链表结构可以克服数组需要预先知道数据大小的缺点,链表结构可以充分地利用计算机内存空间,实现灵活的内存动态管理。
缺点:
链表失去了数组随机读取的优点(没有下标),同时链表由于增加了节点的指针域,空间开销比较大。
单向链表
单向链表简介
单向链表是链表中结构最简单的。
一个单链表的节点(Node)分为两个部分,第一部分保存或者显示关于节点的信息,另一个部分存储下一个节点的地址。
最后一个节点存储地址的部分指向空值。链表有一个头结点。
查找:
从第一个节点开始遍历
删除:
删除节点,把上一个节点的指针指向下一节点(速度比数组快)
插入:
在头部插入
java实现单向链表
package link;
public class SingleLinkTest {
public static void main(String[] args) {
SingleLinkedList singleLinkedList = new SingleLinkedList();
singleLinkedList.addHead('A');
singleLinkedList.addHead('B');
singleLinkedList.addHead('C');
singleLinkedList.addHead('D');
//打印链表
singleLinkedList.display();
System.out.println(singleLinkedList.delete('A'));
singleLinkedList.display();
System.out.println(singleLinkedList.isEmpty());
System.out.println(singleLinkedList.deleteHead());
}
}
//封装单向链表的类
class SingleLinkedList{
private int size; //链表的节点数
private Node head; // head是头结点的指针,引入了一个新类型,node
//构造方法
public SingleLinkedList(){
size = 0;
head = null;
}
//向链表中添加节点(添加到头部)
public Object addHead(Object data){
Node newNode = new Node(data);
if(size == 0){
//空链表
head = newNode;
}else {
//非空链表
newNode.next = head;
head = newNode;
}
size ++;
return newNode;
}
//链表删除头结点,默认链表中是有节点的
public Object deleteHead(){
Object obj = head.data;
head = head.next;
size--;
return obj;
}
//查找指定数据所对应的节点对象
public Node find(Object data){
Node curent = head;
int tmpSize = size;
while (tmpSize > 0){
if (data.equals(curent.data)){
//找到了对象
return curent;
}else {
curent = curent.next;
}
tmpSize--;
}
return null; //如果找不到
}
//判断链表是不是空链表
public boolean isEmpty(){
return size==0;
}
//删除指定节点,删除成功返回true,失败返回false
public boolean delete(Object value){
if(isEmpty()){
//空表
return false;
}
//不是空表
Node current = head;
Node previous = head;//上一个变量
while (!value.equals(current.data)){
if (current.next == null){
//已经扫描到了尾结点,且没找到数据
return false;
}else{
//还没到尾结点
previous = current;
current = current.next;
}
}
// 循环终止了,还会继续执行下面的语句,证明已经找到了要找的节点
//删除找到的节点
if(current == head){
head = head.next;
size --;
}else{
previous.next = current.next;
size --;
}
return true;
}
//遍历输出所有node信息
public void display(){
if (size>0){
//不是空的
Node current = head;
int tmpSize = size;
if (tmpSize == 1){
System.out.println("[" + head.data + "]");
return; // 结束掉方法
}
while (tmpSize>0){
if (current == head){
System.out.print("[" + current.data + "->");
}else if(current.next == null){
//最后一个节点
System.out.print(current.data + "]");
}else {
System.out.print(current.data + "->");
}
tmpSize --;
current = current.next;
}
System.out.println();//输出一个换行符
}else {
//空列表
System.out.println("[]");
}
}
//定义一个私有类
private class Node{
private Object data; //封装在节点里的数据
private Node next; //指针,指向下一个节点
//构造方法
public Node(Object data){
this.data = data;
}
@Override
public String toString() {
return "Node [data=" + data + ", next=" + next + "]";
}
}
}
双端链表
双端链表简介
对于单向链表,我们如果想在尾部添加一个节点,那么必须从头部一直遍历到尾部,找到尾结点,然后在尾结点后面插入一个节点。
这样操作很慢,如果我们在设计链表的时候多个对尾结点的引用,那么会简单很多。
java实现双端链表
package link;
public class DoubleLinkedListTest {
public static void main(String[] args) {
DoubleLinkedList link = new DoubleLinkedList();
link.addHead(1);
link.addHead(0);
link.addTail(2);
link.addTail(3);
link.addTail(2);
link.display();
link.delete(2);
link.display();
System.out.println(link.deleteHead());
link.display();
while(!link.isEmpty()){
System.out.println(link.deleteTail());
}
}
}
class DoubleLinkedList{
private int size; //链表的节点数
private Node head; // head是头结点的指针,引入了一个新类型,node
private Node tail; //指向尾结点的指针
//构造方法
public DoubleLinkedList(){
size = 0;
head = null;
tail = null;
}
//向链表中添加节点(添加到头部)
public Object addHead(Object data){
Node newNode = new Node(data);
if(size == 0){
//空链表
head = newNode;
tail = newNode;
}else {
//非空链表
newNode.next = head;
head = newNode;
}
size ++;
return newNode;
}
//添加尾结点
public Object addTail(Object data){
Node newNode = new Node(data);
if(size == 0) {
//空链表
head = newNode;
tail = newNode;
}else {
tail.next = newNode;
tail = newNode;
}
size ++;
return newNode;
}
//链表删除头结点
public Object deleteHead(){
Object obj = null;
if(size == 0){
//空链表
return obj;
}else if(size == 1){
//链表中只有一个节点
obj = head.data;
head = null;
tail = null;
size --;
}else{
obj = head.data;
head =head.next;
size --;
}
return obj;
}
//删除尾部节点
public Object deleteTail(){
Object obj = null;
if(size == 0){
//空链表
return obj;
}else if(size == 1) {
//链表中只有一个节点
obj = tail.data;
head = null;
tail = null;
size --;
}else {
obj = tail.data;
// int tmp = 1;
Node tmpNode = head;
// while (tmp<size-1){
// tmpNode = tmpNode.next;
// tmp ++;
// }
while (tmpNode.next != tail){
tmpNode = tmpNode.next;
}
tail = tmpNode;
tail.next = null;
size --;
}
return obj;
}
//判断链表是不是空链表
public boolean isEmpty(){
return size==0;
}
//删除指定节点,删除成功返回true,失败返回false
public boolean delete(Object value){
if(isEmpty()){
//空表
return false;
}
//不是空表
Node current = head;
Node previous = head;//上一个变量
while (!value.equals(current.data)){
if (current.next == null){
//已经扫描到了尾结点,且没找到数据
return false;
}else{
//还没到尾结点
previous = current;
current = current.next;
}
}
// 循环终止了,还会继续执行下面的语句,证明已经找到了要找的节点
//删除找到的节点
if(size == 1){
head = null;
tail = null;
}else if(current == head){
head = head.next;
}else if(current == tail){
previous.next = null;
tail = previous;
}else {
previous.next = current.next;
}
size --;
return true;
}
//遍历输出所有node信息
public void display(){
if (size>0){
//不是空的
Node current = head;
int tmpSize = size;
if (tmpSize == 1){
System.out.println("[" + head.data + "]");
return; // 结束掉方法
}
while (tmpSize>0){
if (current == head){
System.out.print("[" + current.data + "->");
}else if(current.next == null){
//最后一个节点
System.out.print(current.data + "]");
}else {
System.out.print(current.data + "->");
}
tmpSize --;
current = current.next;
}
System.out.println();//输出一个换行符
}else {
//空列表
System.out.println("[]");
}
}
//获取节点个数
public int getSize(){
return size;
}
//定义一个私有类
private class Node{
private Object data; //封装在节点里的数据
private Node next; //指针,指向下一个节点
//构造方法
public Node(Object data){
this.data = data;
}
@Override
public String toString() {
return "Node [data=" + data + ", next=" + next + "]";
}
}
}
基于双端链表实现队列
队列:队尾插入,队头删除。先进先出。
package link;
public class QueueDoubleLinkedListTest {
public static void main(String[] args) {
QueueDoubleLinkedList queueDoubleLinkedList = new QueueDoubleLinkedList();
queueDoubleLinkedList.insert(1);
queueDoubleLinkedList.insert(2);
queueDoubleLinkedList.insert(3);
queueDoubleLinkedList.insert(4);
queueDoubleLinkedList.display();
System.out.println(queueDoubleLinkedList.delete());
queueDoubleLinkedList.display();
System.out.println(queueDoubleLinkedList.isEmpty());
System.out.println(queueDoubleLinkedList.getSize());
}
}
class QueueDoubleLinkedList{
private DoubleLinkedList doubleLinkedList;
public QueueDoubleLinkedList(){
doubleLinkedList = new DoubleLinkedList();
}
//插入(链表尾部插入)
public void insert(Object data){
doubleLinkedList.addTail(data);
}
//删除(链表头部删除)
public Object delete(){
return doubleLinkedList.deleteHead();
}
//是否为空
public boolean isEmpty(){
return doubleLinkedList.isEmpty();
}
//获取队列元素个数
public int getSize(){
return doubleLinkedList.getSize();
}
//显示队列元素
public void display(){
doubleLinkedList.display();
}
}