目录
链表的概念
链表是由许多相同数据类型的数据项,按照特定顺序排列而成的线性表。但链表的特性是其各个数据项在计算机内存中存储的位置是不连续且随机存放的,其优点是数据的插入或者删除都相当的方便呢,有新数据加入就向系统申请一块内存空间,而数据删除之后,就可以把这块内存空间还给系统,加入和删除都不需要移动大量的数据。缺点是在查找数据使,无法向数组那样可以随机数据,必须按序查找到该数据为止。
火车就可以看做一个链表
单向链表
一个单向链表节点由两个元素,一个是数据字段和指针多组成,指针会指向下一个节点的地址,一个节点如图所示。
在单项链表中,第一个节点是头结点,它是一个链表的开始,最后一个节点指针指向null;例如下面链表.
链表的创建
节点的创建
要创建链表首先需要创建节,我们创建节点类,定义节点的属性,每个节点有值和下一个节点的地址。
package relinklist;
//
public class Node {
//下一个节点的地址
private Node next;
//节点保存的值
private int val;
public Node() {
}
public Node(int val) {
this.val = val;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
public int getVal() {
return val;
}
public void setVal(int val) {
this.val = val;
}
}
创建链表
public class LinkList {
//链表的头结点
private Node head;
//链表有效节点个数
private int size;
//无参构造方法
public LinkList() {
}
//有参构造方法
public LinkList(int val) {
Node node = new Node(val);
this.head = node;
this.size = 1;
}
添加节点
向链表中添加节点分为三种方式1、头插法 2、尾插法 3、向索引指向位置插入
头插法
向链表最前方插入节点,需要将新节点的指针指向链表当前的头结点,再将头节点移向新节点,让新节点来做头节点。
/**
* 向链表中添加节点(头插)
*/
public void addNode(int val) {
if (head == null) {
//当链表为空时,将新节点赋给头节点
head = new Node(val);
} else {
Node newNode = new Node();
newNode.setVal(val);
newNode.setNext(head);
head = newNode;
}
size++;
}
尾插法
让原链表的,指向新创建的节点。
/**
* 向链表的尾部插入节点
*
* @param val 插入节点的值
*/
public void addNodeEnd(int val) {
if (this.head == null) {
//链表为空,将新节点赋给头结点
head = new Node(val);
} else {
Node x = head;
for (int i = 0; i < size - 1; i++) {
x = x.getNext();
}
x.setNext(new Node(val));
}
size++;
}
按照索引插入新节点
首先需要找到索引位置的前节点节,将索引处节点与前节点连接断开,将前节点的指针指向新节点,新节点的指针指向之前的索引处节点。使用时需要判断索引是否是有效的。
例如向下面链表索引2,添加值为2的节点
/**
* 向链表中的目标位置插入节点
*
* @param index 目标位置
* @param val 插入节点值
*/
public void addNodeIndex(int index, int val) {
if (index > size || index < 0) {
System.out.println("无效下标");
return;
} else if (index == 0) {
//当索引指向头节点时
addNode(val);
} else if (index == size) {
//当索引指向链表最后NULL时
addNodeEnd(val);
} else {
Node node = head;
Node x = new Node(val);
for (int i = 0; i < size - 1; i++) {
if (i == index - 1) {
x.setNext(node.getNext());
node.setNext(x);
size++;
return;
}
node = node.getNext();
}
}
}
删除节点
删除第一个值为val的节点
删除第一个值为val的节点,需要前节点指向指向值为val节点的后节点,使val节点没有节点指向它
删除链表中第一个值3的节点
先判断知否有值为val的节点
/**
* 判断链表中是否有包含值为val的节点
* @param val 节点的值
* @return 有值为val的节点返回true,没有返回false
*/
public boolean contains(int val) {
return getNodeIndex(val) != -1;
}
进行删除操作
/**
* 删除第一次出现值为val的节点
*
* @param val 删除节点的值
*/
public void deleteNodeVal(int val) {
if (contains((val))) {
while (head.getVal() == val) {
if (head.getNext() != null) {
Node node = head;
head = head.getNext();
node.setNext(null);
size--;
return;
} else {
head = null;
size--;
return;
}
}
Node x = head;
while (x.getNext() != null) {
if (x.getNext().getVal() == val) {
Node node = x.getNext();
x.setNext(x.getNext().getNext());
node.setNext(null);
size--;
return;
} else {
x = x.getNext();
}
}
}
System.out.println("没有值为" + val + "的节点");
}
删除索引指向的节点并返回该节点的值
删除索引指向的节点,需要前节点指向待删除节点的后节点,使待删除节点没有节点指向它
删除索引为1的节点
先判断索引对否有效
/**
* 判断索引的合法性,是否为负数,是否小于size
*
* @param index 索引
* @return 为负数或者不小于size返回false,在区间内返回true
*/
private boolean rangeCheck(int index) {
if (index < 0 || index >= size) {
return false;
}
return true;
}
进行删除操作
/**
* 删除索引指向的节点并返回节点原先的值
*
* @param index
* @return
*/
public int deleteNodeReVal(int index) {
if (rangeCheck(index)) {
int oldVal = getIndexNode(index);
if (index == 0) {
Node x = head;
head = head.getNext();
x.setNext(null);
size--;
return oldVal;
}
Node x = head;
for(int i = 0; i < index - 1; i ++){
x = x.getNext();
}
Node node = x.getNext();
x.setNext(x.getNext().getNext());
node.setNext(null);
size --;
return oldVal;
}
System.err.println("index illegal! get error");
return -1;
}
删除头结点
让头结点后移到头结点指向的后一节点,原先的头结点指向null;
使用删除索引指向的节点,删除索引为0的节点
/**
* 删除头节点
*/
public void deleteFirstNode(){
deleteNodeReVal(0);
}
删除尾节点
让最后一个节点的前一个节点指向null;
使用删除索引指向的节点,删除索引为size-1(有效节点数量 - 1)的节点
/**
* 删除尾节点
*/
public void deleteEndNode(){
deleteNodeReVal(size - 1);
}
删除所有值为val的节点
删除所有值为2的节点
当链表的头节点的值就位2时,需要先进行从头删除,找出删除后链表的头结点
再对头节点不为2之后的值为2的节点进行删除
/**
*删除所有值为val的节点
* @param val 节点包含的值
*/
public void deleteSameNodeVal(int val){
if(contains(val)){
while(head.getVal() == val){
if(head.getNext() != null){
Node node = head;
head = head.getNext();
node.setNext(null);
size--;
}else{
head = null;
size--;
return;
}
}
Node x = head;
while(x.getNext() != null){
if(x.getNext().getVal() == val){
Node node = x.getNext();
x.setNext(x.getNext().getNext());
node.setNext(null);
size --;
}else{
x = x.getNext();
}
}
}
}
修改节点值
修改只需通索引找到该节点,再进行修改错
修改索引指向的节点并返回原先的值
/**
* 修改索引指向节点的值并返回原始先的值
*
* @param index 索引
* @param val 修改节点的值
* @return 返回节点原先的值
*/
public int setIndexNode(int index, int val) {
if (rangeCheck(index)) {
int oldVal = getIndexNode(index);
Node node = head;
for (int i = 0; i < index; i++) {
node = node.getNext();
}
node.setVal(val);
return oldVal;
}
System.err.println("index illegal! get error");
return -1;
}
查询节点
通过索引查找索引指向的节点,或者通过值查找第一个值为val的节点
/**
* 查询索引 index 所指向节点的值
*
* @param index 索引
* @return 返回查询节点的值
*/
public int getIndexNode(int index) {
if (rangeCheck(index)) {
Node x = head;
for (int i = 0; i < index; i++) {
x = x.getNext();
}
return x.getVal();
}
System.err.println("index illegal! get error");
return -1;
}
/**
* 查询第一个值为val的节点的索引
*
* @param val 将要节点的值
* @return 返回节点的索引
*/
public int getNodeIndex(int val) {
int index = 0;
for (Node node = head; node != null; node = node.getNext()) {
if (val == node.getVal()) {
return index;
}
index++;
}
//链表中没有值为val的节点
return -1;
}
将链表打印输出并返回有效节点个数
/**
* 打印双向链表
*
* @return 返回双向链表每个节点的值
*/
public StringBuffer toPrint() {
StringBuffer sb = new StringBuffer();
if (size == 0) {
return sb.append("null");
}
Node node = head;
for (int i = 0; i < size; i++) {
sb.append(node.getVal());
sb.append("-->");
node = node.getNext();
}
sb.append("null");
return sb;
}
/**
* 返回size的值
*
* @return 返回size
*/
public int getSize() {
return size;
}
}
双向链表
双向链表的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
节点的创建
public class Node {
private Node prev;
private int val;
private Node next;
public Node() {
}
public Node(int val) {
this.val = val;
}
public Node(Node prev, int val, Node next) {
this.prev = prev;
this.val = val;
this.next = next;
}
public Node getPrev() {
return prev;
}
public void setPrev(Node prev) {
this.prev = prev;
}
public int getVal() {
return val;
}
public void setVal(int val) {
this.val = val;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
链表的创建
public class DoubleLinkList {
private Node head;
private Node tail;
private int size;
}
增加节点
头插法
将新节点的后指针,指向当前链表的头节点,头节点的前指针,指向新节点,最后将新节点赋给头节点
/**
* 头插法
*
* @param val 插入节点的值
*/
public void addHead(int val) {
Node node = new Node(null, val, head);
if (tail != null) {
head.setPrev(node);
} else {
tail = node;
}
head = node;
size++;
}
尾插法
将新节点的前指针,指向尾节点,尾节点的后指针,指向新节点,将新节点赋给尾节点
/**
* 尾插法
*
* @param val 插入节点的值
*/
public void addEnd(int val) {
Node node = new Node(tail, val, null);
if (tail == null) {
addHead(val);
} else {
tail.setNext(node);
tail = node;
size++;
}
}
根据索引插入节点
由于双向链表可以从头遍历到尾,或者从尾遍历到头,当我们有100个节点,插入节点位置是10,我们从头找开始很快,当位置为90时,我们发现从尾部开始找很快,所以我们创建一个方法来判断从头开始找还是从尾部开始找
/**
* 判断索引的节点是从头插入还是从尾插入
*
* @param index 索引
* @return 返回 1 则从头插入,返回 0则从尾部插入,返回-1是无效下标
*/
private int headOrEnd(int index) {
if (checkIndex(index)) {
if (index < size / 2) {
return 1;
} else {
return 0;
}
}
return -1;
}
然后进行擦插入操作,将索引指向节点的前置节点与新节点相连1操作,再将新节点与索引指向节点相连2操作
/**
* 根据索引插入节点
*
* @param index 索引
* @param val 节点值
*/
public void addAnyIndex(int index, int val) {
if (index == 0) {
addHead(val);
return;
} else if (index == size) {
addEnd(val);
return;
}
Node node = new Node(val);
if (headOrEnd(index) == 1) {
//头部插入
Node h = head;
for (int i = 0; i < index; i++) {
h = h.getNext();
}
Node a = h.getPrev();
node.setPrev(a);
a.setNext(node);
node.setNext(h);
h.setPrev(node);
} else if (headOrEnd(index) == 0) {
//尾部插入
Node t = tail;
for (int i = 0; i < size - index; i++) {
t = t.getPrev();
}
Node a = t.getNext();
node.setNext(a);
a.setPrev(node);
node.setPrev(t);
t.setNext(node);
} else {
System.out.println("索引不合法");
return;
}
size++;
}
查找节点
根据索引查找
需要判断索引的合法性
/**
* 判断索引的合法性
*
* @param index 索引
* @return 返回false 索引不合法,返回true 索引合法
*/
private Boolean checkIndex(int index) {
if (index < 0 || index >= size) {
return false;
} else {
return true;
}
}
进行查找
/**
* 根据索引查询目标节点
*
* @param index 索引
* @return 返回目标节点的值, 返回-1表示无效索引
*/
public int getIndexNodeVal(int index) {
int count = 0;
if (headOrEnd(index) == 1) {
//从头结点开始查询
Node node = head;
while (count < index) {
node = node.getNext();
count++;
}
return node.getVal();
}
if (headOrEnd(index) == 0) {
//从尾节点开始查询
Node node = tail;
while (count < size - 1 - index) {
node = node.getPrev();
count++;
}
return node.getVal();
}
System.err.println("无效索引");
return -1;
}
根据值从头查找第一个值为val的节点返回索引
/**
* 根据值从头结点开始查询第一个值为val的节点返回节点索引
*
* @param val 查询节点值
* @return 查询到的节点索引
*/
public int getValHeadNodeIndex(int val) {
Node node = head;
int index = 0;
while (node != null) {
if (node.getVal() == val) {
return index;
}
index++;
node = node.getNext();
}
//查找不到值为val的节点返回-1
return -1;
}
根据值从尾查找第一个值为val的节点返回索引
/**
* 根据值从尾结点开始查询第一个值为val的节点返回节点索引
*
* @param val 查询节点值
* @return 查询到的节点索引
*/
public int getValEndNodeIndex(int val) {
Node node = tail;
int index = 0;
while (node != null) {
if (node.getVal() == val) {
return size - 1 - index;
}
index++;
node = node.getPrev();
}
//查找不到值为val的节点返回-1
return -1;
}
删除节点
原理
先找到待删除节点,将待删除节点的后置节点赋给一个新节点x,再将待删除节点与x节点相连,带删除节点的前指针和后指针指向空。先执行1操作,再执行2、3操作,最后4、5操作
根据索引删除节点
先根据值找到待删除节点之后执行删除操作
/**
* 删除索引指向的节点,并返回该节点的值
*
* @param index 索引
* @return 删除节点的值
*/
public int deleteIndex(int index) {
int val = 0;
if (checkIndex(index)) {
if (index == size - 1) {
//链表只有一个节点时;
if (size == 1) {
val = head.getVal();
head = tail = null;
size--;
return val;
}
//不止一个节点
val = tail.getVal();
Node x = tail.getPrev();
tail.setPrev(null);
x.setNext(null);
tail = x;
} else if (index == 0) {
val = head.getVal();
Node x = head.getNext();
x.setPrev(null);
head.setNext(null);
head = x;
} else {
Node node = head;
for (int i = 0; i < index; i++) {
node = node.getNext();
}
val = node.getVal();
Node x = node.getPrev();
Node n = node.getNext();
x.setNext(n);
n.setPrev(x);
}
size--;
return val;
}
//索引不合法返回-1
return -1;
}
根据值从头开始删除第一个值为val节点
/**
* 从头开始删除第一个值为val的节点
*
* @param val 删除节点的值
*/
public void deleteHeadFirstVal(int val) {
int index = getValHeadNodeIndex(val);
deleteIndex(index);
}
根据值从尾开始删除第一个值为val节点
/**
* 从尾开始删除第一个值为val的节点
* @param val 删除节点的值
*/
public void deleteTailFirstVal(int val) {
int index = getValEndNodeIndex(val);
deleteIndex(index);
}
删除所有值为val的节点
如果头结点就是待删除节点,则先处理头结点,当头结点不为待删除值时,处理后面的节点
/**
* 删除所有值为val的节点
*
* @param val 节点值
*/
public void deleteSameVal(int val) {
if (getValHeadNodeIndex(val) != -1) {
while (head.getVal() == val) {
if (head.getNext() != null) {
Node x = head.getNext();
head.setNext(null);
x.setPrev(null);
head = x;
size--;
} else {
head = tail = null;
size--;
return;
}
}
Node node = head;
while (node.getNext() != null) {
if (node.getVal() == val) {
Node x = node.getNext();
Node h = node.getPrev();
x.setPrev(h);
h.setNext(x);
node.setNext(null);
node.setPrev(null);
node = x;
size--;
} else {
node = node.getNext();
}
}
if (node.getVal() == val) {
node.getPrev().setNext(null);
tail = node.getPrev();
node.setPrev(null);
size--;
}
return;
}
System.out.println("链表中没有此节点");
}
修改节点
根据索引修改节点的值
/**
* 根据索引修改该节点,并返回修改前的值
*
* @param index 索引
* @param val 修改的值
* @return 返回修改前的值
*/
public int setIndexVal(int index, int val) {
if (headOrEnd(index) == 1) {
Node node = head;
for (int i = 0; i < index; i++) {
node = node.getNext();
}
int reVal = node.getVal();
node.setVal(val);
return reVal;
} else if (headOrEnd(index) == 0) {
Node node = tail;
for (int i = 0; i < size - 1 - index; i++) {
node = node.getPrev();
}
int reVal = node.getVal();
node.setVal(val);
return reVal;
}
System.err.println("无效索引");
return -1;
}
将链表打印输出并返回有效节点个数
/**
* 打印双向链表
*
* @return 返回双向链表每个节点的值
*/
public StringBuffer toPrint() {
StringBuffer sb = new StringBuffer();
if (size == 0) {
return sb.append("null");
}
Node node = head;
for (int i = 0; i < size; i++) {
sb.append(node.getVal());
sb.append("-->");
node = node.getNext();
}
sb.append("null");
return sb;
}
/**
* 返回size的值
*
* @return 返回size
*/
public int getSize() {
return size;
}
单链表源码
节点代码
public class Node {
private Node next;
private int val;
public Node() {
}
public Node(int val) {
this.val = val;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
public int getVal() {
return val;
}
public void setVal(int val) {
this.val = val;
}
}
链表代码
public class LinkList {
private Node head;
private int size;
public LinkList() {
}
public LinkList(int val) {
Node node = new Node(val);
this.head = node;
this.size = 1;
}
/**
* 向链表中添加节点(头插)
*/
public void addNode(int val) {
if (head == null) {
head = new Node(val);
} else {
Node newNode = new Node();
newNode.setVal(val);
newNode.setNext(head);
head = newNode;
}
size++;
}
/**
* 向链表的尾部插入节点
*
* @param val 插入节点的值
*/
public void addNodeEnd(int val) {
if (this.head == null) {
head = new Node(val);
} else {
Node x = head;
for (int i = 0; i < size - 1; i++) {
x = x.getNext();
}
x.setNext(new Node(val));
}
size++;
}
/**
* 向链表中的目标位置插入节点
*
* @param index 目标位置
* @param val 插入节点值
*/
public void addNodeIndex(int index, int val) {
if (index > size || index < 0) {
System.out.println("无效下标");
return;
} else if (index == 0) {
//当索引指向头节点时
addNode(val);
} else if (index == size) {
//当索引指向链表最后NULL时
addNodeEnd(val);
} else {
Node node = head;
Node x = new Node(val);
for (int i = 0; i < size - 1; i++) {
if (i == index - 1) {
x.setNext(node.getNext());
node.setNext(x);
size++;
return;
}
node = node.getNext();
}
}
}
/**
* 查询索引 index 所指向节点的值
*
* @param index 索引
* @return 返回查询节点的值
*/
public int getIndexNode(int index) {
if (rangeCheck(index)) {
Node x = head;
for (int i = 0; i < index; i++) {
x = x.getNext();
}
return x.getVal();
}
System.err.println("index illegal! get error");
return -1;
}
/**
* 查询第一个值为val的节点的索引
*
* @param val 将要节点的值
* @return 返回节点的索引
*/
public int getNodeIndex(int val) {
int index = 0;
for (Node node = head; node != null; node = node.getNext()) {
if (val == node.getVal()) {
return index;
}
index++;
}
//链表中没有值为val的节点
return -1;
}
/**
* 修改索引指向节点的值并返回原始先的值
*
* @param index 索引
* @param val 修改节点的值
* @return 返回节点原先的值
*/
public int setIndexNode(int index, int val) {
if (rangeCheck(index)) {
int oldVal = getIndexNode(index);
Node node = head;
for (int i = 0; i < index; i++) {
node = node.getNext();
}
node.setVal(val);
return oldVal;
}
System.err.println("index illegal! get error");
return -1;
}
/**
* 删除第一次出现值为val的节点
*
* @param val 删除节点的值
*/
public void deleteNodeVal(int val) {
if (contains((val))) {
while (head.getVal() == val) {
if (head.getNext() != null) {
Node node = head;
head = head.getNext();
node.setNext(null);
size--;
return;
} else {
head = null;
size--;
return;
}
}
Node x = head;
while (x.getNext() != null) {
if (x.getNext().getVal() == val) {
Node node = x.getNext();
x.setNext(x.getNext().getNext());
node.setNext(null);
size--;
return;
} else {
x = x.getNext();
}
}
}
System.out.println("没有值为" + val + "的节点");
}
/**
* 删除索引指向的节点并返回节点原先的值
*
* @param index
* @return
*/
public int deleteNodeReVal(int index) {
if (rangeCheck(index)) {
int olaVal = getIndexNode(index);
if (index == 0) {
Node x = head;
head = head.getNext();
x.setNext(null);
size--;
return olaVal;
}
Node x = head;
for(int i = 0; i < index - 1; i ++){
x = x.getNext();
}
Node node = x.getNext();
x.setNext(x.getNext().getNext());
node.setNext(null);
size --;
return olaVal;
}
System.err.println("index illegal! get error");
return -1;
}
/**
* 删除头节点
*/
public void deleteFirstNode(){
deleteNodeReVal(0);
}
/**
* 删除尾节点
*/
public void deleteEndNode(){
deleteNodeReVal(size - 1);
}
/**
*删除所有值为val的节点
* @param val 节点包含的值
*/
public void deleteSameNodeVal(int val){
if(contains(val)){
while(head.getVal() == val){
if(head.getNext() != null){
Node node = head;
head = head.getNext();
node.setNext(null);
size--;
}else{
head = null;
size--;
return;
}
}
Node x = head;
while(x.getNext() != null){
if(x.getNext().getVal() == val){
Node node = x.getNext();
x.setNext(x.getNext().getNext());
node.setNext(null);
size --;
}else{
x = x.getNext();
}
}
}
}
/**
* 判断索引的合法性,是否为负数,是否小于size
*
* @param index 索引
* @return 为负数或者不小于size返回false,在区间内返回true
*/
private boolean rangeCheck(int index) {
if (index < 0 || index >= size) {
return false;
}
return true;
}
/**
* 判断链表中是否有包含值为val的节点
* @param val 节点的值
* @return 有值为val的节点返回true,没有返回false
*/
public boolean contains(int val) {
return getNodeIndex(val) != -1;
}
/**
* 打印输出链表
*
* @return 返回链表的每个节点的值
*/
public String toPrint() {
String s = "";
if (size == 0) {
s += null;
return s;
} else {
Node node = head;
for (int i = 0; i < size; i++) {
s += node.getVal();
if (node.getNext() != null) {
s += "-->";
}
node = node.getNext();
}
s += "-->null";
}
return s;
}
/**
* 返回链表长度
*
* @return 返回size的值
*/
public int getSize() {
return size;
}
}
测试代码
public class Test {
public static void main(String[] args) {
LinkList linkList = new LinkList();
System.out.println("===============头插法==============");
linkList.addNode(10);
linkList.addNode(20);
System.out.println(linkList.toPrint());
System.out.println("===============尾插法==============");
linkList.addNodeEnd(1);
System.out.println(linkList.toPrint());
System.out.println("==============指定下标插入==============");
linkList.addNodeIndex(0,30);
System.out.println(linkList.toPrint());
linkList.addNodeIndex(4,2);
System.out.println(linkList.toPrint());
linkList.addNodeIndex(2,15);
System.out.println(linkList.toPrint());
linkList.addNodeIndex(5,1);
System.out.println(linkList.toPrint());
System.out.println("==============查询指定索引的节点===================");
System.out.println(linkList.getIndexNode(1));
System.out.println("==============查询值为val的第一个的节点的索引===================");
System.out.println(linkList.getNodeIndex(15));
System.out.println("=========判断链表中是否有值为val的节点==============");
System.out.println(linkList.contains(11));
System.out.println(linkList.contains(1));
System.out.println("==============修改指定节点的值并返回原先的值===================");
System.out.println("原先的值为" + linkList.setIndexNode(4,3) + "现在的值为" + linkList.getIndexNode(4));
System.out.println("==========添加节点=============================");
linkList.addNodeIndex(1,30);
linkList.addNodeIndex(3,30);
linkList.addNodeIndex(5,30);
System.out.println("=============删除值为val的第一个节点========================");
System.out.println(linkList.toPrint());
linkList.deleteNodeVal(30);
System.out.println(linkList.toPrint());
linkList.deleteNodeVal(10);
System.out.println(linkList.toPrint());
linkList.deleteNodeVal(2);
System.out.println(linkList.toPrint());
System.out.println("============删除所有值为val的节点===========================");
linkList.deleteSameNodeVal(30);
System.out.println(linkList.toPrint());
System.out.println("=================添加节点====================");
linkList.addNode(30);
linkList.addNodeIndex(2,10);
linkList.addNodeIndex(5,2);
linkList.addNode(40);
System.out.println(linkList.toPrint());
System.out.println("===========根据索引删除节点并返回原先的值==========");
System.out.println("原先的值为" + linkList.deleteNodeReVal(0));
System.out.println(linkList.toPrint());
System.out.println("原先的值为" + linkList.deleteNodeReVal(2));
System.out.println(linkList.toPrint());
System.out.println("原先的值为" + linkList.deleteNodeReVal(5));
System.out.println(linkList.toPrint());
System.out.println("=========添加节点==============================");
linkList.addNodeIndex(3,5);
linkList.addNode(40);
linkList.addNode(50);
linkList.addNodeEnd(0);
System.out.println(linkList.toPrint());
System.out.println("======删除头节点========");
linkList.deleteFirstNode();
System.out.println(linkList.toPrint());
System.out.println("=====删除尾节点====================");
linkList.deleteEndNode();
System.out.println(linkList.toPrint());
System.out.println("=========添加节点========");
linkList.addNodeEnd(1);
System.out.println(linkList.toPrint());
System.out.println("==============链表所有节点值都一样删除所有节点=====================");
//链表所有节点值都一样删除所有节点
LinkList linkList1 = new LinkList();
linkList1.addNode(10);
linkList1.addNode(10);
linkList1.addNode(10);
linkList1.addNode(10);
linkList1.addNode(10);
System.out.println(linkList1.toPrint());
linkList1.deleteSameNodeVal(10);
System.out.println(linkList1.toPrint());
}
}
双向链表源码
节点代码
public class Node {
private Node prev;
private int val;
private Node next;
public Node() {
}
public Node(int val) {
this.val = val;
}
public Node(Node prev, int val, Node next) {
this.prev = prev;
this.val = val;
this.next = next;
}
public Node getPrev() {
return prev;
}
public void setPrev(Node prev) {
this.prev = prev;
}
public int getVal() {
return val;
}
public void setVal(int val) {
this.val = val;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
链表代码
public class DoubleLinkList {
private Node head;
private Node tail;
private int size;
/**
* 头插法
*
* @param val 插入节点的值
*/
public void addHead(int val) {
Node node = new Node(null, val, head);
if (tail != null) {
head.setPrev(node);
} else {
tail = node;
}
head = node;
size++;
}
/**
* 尾插法
*
* @param val 插入节点的值
*/
public void addEnd(int val) {
Node node = new Node(tail, val, null);
if (tail == null) {
addHead(val);
} else {
tail.setNext(node);
tail = node;
size++;
}
}
/**
* 根据索引插入节点
*
* @param index 索引
* @param val 节点值
*/
public void addAnyIndex(int index, int val) {
if (index == 0) {
addHead(val);
return;
} else if (index == size) {
addEnd(val);
return;
}
Node node = new Node(val);
if (headOrEnd(index) == 1) {
//头部插入
Node h = head;
for (int i = 0; i < index; i++) {
h = h.getNext();
}
Node a = h.getPrev();
node.setPrev(a);
a.setNext(node);
node.setNext(h);
h.setPrev(node);
} else if (headOrEnd(index) == 0) {
//尾部插入
Node t = tail;
for (int i = 0; i < size - index; i++) {
t = t.getPrev();
}
Node a = t.getNext();
node.setNext(a);
a.setPrev(node);
node.setPrev(t);
t.setNext(node);
} else {
System.out.println("索引不合法");
return;
}
size++;
}
/**
* 判断索引的合法性
*
* @param index 索引
* @return 返回false 索引不合法,返回true 索引合法
*/
private Boolean checkIndex(int index) {
if (index < 0 || index >= size) {
return false;
} else {
return true;
}
}
/**
* 判断索引的节点是从头插入还是从尾插入
*
* @param index 索引
* @return 返回 1 则从头插入,返回 0则从尾部插入,返回-1是无效下标
*/
private int headOrEnd(int index) {
if (checkIndex(index)) {
if (index < size / 2) {
return 1;
} else {
return 0;
}
}
return -1;
}
/**
* 根据值从头结点开始查询第一个值为val的节点返回节点索引
*
* @param val 查询节点值
* @return 查询到的节点索引
*/
public int getValHeadNodeIndex(int val) {
Node node = head;
int index = 0;
while (node != null) {
if (node.getVal() == val) {
return index;
}
index++;
node = node.getNext();
}
//查找不到值为val的节点返回-1
return -1;
}
/**
* 根据值从尾结点开始查询第一个值为val的节点返回节点索引
*
* @param val 查询节点值
* @return 查询到的节点索引
*/
public int getValEndNodeIndex(int val) {
Node node = tail;
int index = 0;
while (node != null) {
if (node.getVal() == val) {
return size - 1 - index;
}
index++;
node = node.getPrev();
}
//查找不到值为val的节点返回-1
return -1;
}
/**
* 根据索引查询目标节点
*
* @param index 索引
* @return 返回目标节点的值, 返回-1表示无效索引
*/
public int getIndexNodeVal(int index) {
int count = 0;
if (headOrEnd(index) == 1) {
//从头结点开始查询
Node node = head;
while (count < index) {
node = node.getNext();
count++;
}
return node.getVal();
}
if (headOrEnd(index) == 0) {
//从尾节点开始查询
Node node = tail;
while (count < size - 1 - index) {
node = node.getPrev();
count++;
}
return node.getVal();
}
System.err.println("无效索引");
return -1;
}
/**
* 查询头结点的值
*
* @return 返回头节点点的值
*/
public int getHead() {
return getIndexNodeVal(0);
}
/**
* 查询尾节点的值
*
* @return 返回尾节点的值
*/
public int getTail() {
return getIndexNodeVal(size - 1);
}
/**
* 从头开始删除第一个值为val的节点
*
* @param val 删除节点的值
*/
public void deleteHeadFirstVal(int val) {
int index = getValHeadNodeIndex(val);
deleteIndex(index);
}
/**
* 从尾开始删除第一个值为val的节点
* @param val 删除节点的值
*/
public void deleteTailFirstVal(int val) {
int index = getValEndNodeIndex(val);
deleteIndex(index);
}
/**
* 删除头结点,并返回头结点的值
*
* @return 返回删除头结点的值
*/
public int deleteHead() {
return deleteIndex(0);
}
/**
* 删除尾结点,并返回尾结点的值
*
* @return 返回被删除尾结点的值
*/
public int deleteTail() {
return deleteIndex(size - 1);
}
/**
* 删除索引指向的节点,并返回该节点的值
*
* @param index 索引
* @return 删除节点的值
*/
public int deleteIndex(int index) {
int val = 0;
if (checkIndex(index)) {
if (index == size - 1) {
//链表只有一个节点时;
if (size == 1) {
val = head.getVal();
head = tail = null;
size--;
return val;
}
//不止一个节点
val = tail.getVal();
Node x = tail.getPrev();
tail.setPrev(null);
x.setNext(null);
tail = x;
} else if (index == 0) {
val = head.getVal();
Node x = head.getNext();
x.setPrev(null);
head.setNext(null);
head = x;
} else {
Node node = head;
for (int i = 0; i < index; i++) {
node = node.getNext();
}
val = node.getVal();
Node x = node.getPrev();
Node n = node.getNext();
x.setNext(n);
n.setPrev(x);
}
size--;
return val;
}
//索引不合法返回-1
return -1;
}
/**
* 删除所有值为val的节点
*
* @param val 节点值
*/
public void deleteSameVal(int val) {
if (getValHeadNodeIndex(val) != -1) {
while (head.getVal() == val) {
if (head.getNext() != null) {
Node x = head.getNext();
head.setNext(null);
x.setPrev(null);
head = x;
size--;
} else {
head = tail = null;
size--;
return;
}
}
Node node = head;
while (node.getNext() != null) {
if (node.getVal() == val) {
Node x = node.getNext();
Node h = node.getPrev();
x.setPrev(h);
h.setNext(x);
node.setNext(null);
node.setPrev(null);
node = x;
size--;
} else {
node = node.getNext();
}
}
if (node.getVal() == val) {
node.getPrev().setNext(null);
tail = node.getPrev();
node.setPrev(null);
size--;
}
return;
}
System.out.println("链表中没有此节点");
}
/**
* 根据索引修改该节点,并返回修改前的值
*
* @param index 索引
* @param val 修改的值
* @return 返回修改前的值
*/
public int setIndexVal(int index, int val) {
if (headOrEnd(index) == 1) {
Node node = head;
for (int i = 0; i < index; i++) {
node = node.getNext();
}
int reVal = node.getVal();
node.setVal(val);
return reVal;
} else if (headOrEnd(index) == 0) {
Node node = tail;
for (int i = 0; i < size - 1 - index; i++) {
node = node.getPrev();
}
int reVal = node.getVal();
node.setVal(val);
return reVal;
}
System.err.println("无效索引");
return -1;
}
/**
* 打印双向链表
*
* @return 返回双向链表每个节点的值
*/
public StringBuffer toPrint() {
StringBuffer sb = new StringBuffer();
if (size == 0) {
return sb.append("null");
}
Node node = head;
for (int i = 0; i < size; i++) {
sb.append(node.getVal());
sb.append("-->");
node = node.getNext();
}
sb.append("null");
return sb;
}
/**
* 返回size的值
*
* @return 返回size
*/
public int getSize() {
return size;
}
}
测试代码
public class Test {
public static void main(String[] args) {
DoubleLinkList linkList = new DoubleLinkList();
System.out.println("========头插法======");
linkList.addHead(11);
linkList.addHead(20);
System.out.println(linkList.toPrint());
System.out.println("========尾插法======");
linkList.addEnd(10);
linkList.addEnd(20);
System.out.println(linkList.toPrint());
System.out.println("=====根据索引插入============");
linkList.addAnyIndex(0,30);
linkList.addAnyIndex(0,40);
linkList.addAnyIndex(0,50);
linkList.addAnyIndex(0,70);
linkList.addAnyIndex(2,55);
linkList.addAnyIndex(2,56);
linkList.addAnyIndex(4,51);
linkList.addAnyIndex(6,45);
linkList.addAnyIndex(10,15);
System.out.println(linkList.getSize());
System.out.println(linkList.toPrint());
linkList.addAnyIndex(-1,10);
linkList.addAnyIndex(3,55);
linkList.addAnyIndex(3,55);
System.out.println(linkList.getSize());
System.out.println(linkList.toPrint());
System.out.println("=========根据val从头节点查询第一个值为val的节点============");
System.out.println(linkList.getValHeadNodeIndex(55));
System.out.println("=========根据val从尾节点查询第一个值为val的节点============");
System.out.println(linkList.getValEndNodeIndex(55));
System.out.println("=========根据索引查询目标节点的值==================");
System.out.println(linkList.toPrint());
System.out.println(linkList.getIndexNodeVal(0));
System.out.println(linkList.getIndexNodeVal(-1));
System.out.println("=======查询头节点的值=======");
System.out.println(linkList.getHead());
System.out.println("=======查询尾节点的值=======");
System.out.println(linkList.getTail());
System.out.println("========从头结点开始删除值为val的第一个节点");
System.out.println(linkList.toPrint());
linkList.deleteHeadFirstVal(70);
System.out.println(linkList.toPrint());
linkList.deleteHeadFirstVal(55);
linkList.deleteHeadFirstVal(20);
linkList.deleteHeadFirstVal(20);
System.out.println(linkList.toPrint());
System.out.println("======添加节点====");
linkList.addAnyIndex(8,55);
System.out.println(linkList.toPrint());
System.out.println("========从尾节点开始删除值为val的第一个节点");
linkList.deleteTailFirstVal(55);
System.out.println(linkList.toPrint());
System.out.println("=====删除索引指向的节点返回删除前该节点的值=======");
System.out.println(linkList.deleteIndex(1));
System.out.println(linkList.deleteIndex(0));
System.out.println(linkList.deleteIndex(8));
System.out.println(linkList.toPrint());
System.out.println("======删除头节点=====");
System.out.println(linkList.deleteHead());
System.out.println(linkList.toPrint());
System.out.println("======删除尾节点=====");
System.out.println(linkList.deleteTail());
System.out.println(linkList.toPrint());
System.out.println("============添加节点================");
linkList.addAnyIndex(5,55);
linkList.addAnyIndex(2,55);
linkList.addAnyIndex(4,55);
linkList.addAnyIndex(6,55);
linkList.addAnyIndex(3,55);
linkList.addAnyIndex(11,55);
System.out.println(linkList.toPrint());
System.out.println("=====删除所有值为val的节点==========");
linkList.deleteSameVal(55);
System.out.println(linkList.toPrint());
System.out.println("=====修改索引指向节点的值====");
System.out.println(linkList.setIndexVal(2,35));
System.out.println(linkList.toPrint());
}
}