一、链表是什么
链表是一种物理存储结构上非连续的存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的。主要由头节点以及其他节点所组成,每一个节点都有指向写一个节点的指向,尾节点指向空(null)。概念问题比较简单,接下来我们具体来看一下链表的具体问题。
二、链表实际问题
1.链表增删改查
注意:链表的增删改查最重要的就是找到他的前驱节点,因为链表不是物理存储,他的存储是指向下一个节点,这样一个一个指向,所构成的完整链表,所以前驱节点是最重要的!!!
先定义链表的参数:
private Node head = null;
private int size = 0;
下面是链表的增加节点的代码:
// 在链表中添加一个新的节点,头部添加
public void addFirst(int val){
Node newNode = new Node();
newNode.val = val;
if(head == null){
head = newNode;
size++;
}else{
newNode.next = head;
head = newNode;
size++;
}
}
// 链表的一个索引处添加一个元素
public void add(int index,int val){
Node newNode = new Node();
if(isAddIllegal(index)){
if(index == 0){
addFirst(val);
size++;
}else {
newNode.val = val;
Node x = head;
for (int i = 0; i < index-1; i++) {
x = x.next;
}
newNode.next = x.next;
x.next = newNode;
size++;
}
}
}
// 链表的尾部添加元素
public void addLast(int val){
add(size,val);
}
在头部添加新节点时一定要注意添加后,一定要执行head = newNode,让新的节点为头节点。
在链表的某个索引处添加一定要添加index的合法性,代码如下:
private boolean isAddIllegal(int index){
if(index < 0 || index > size){
return false;
}
return true;
}
下面是链表的其他操作代码:
// 查询索引为index的元素值是多少
public int get(int index){
if(isIllegal(index)){
Node x = head;
for (int i = 0; i < index; i++) {
x = x.next;
}
return x.val;
}
return -1;
}
// 查询第一个值为val的元素索引的位置
public int getIndex(int val){
Node x = head;
if(x.val == val){
return 0;
}
for (int i = 0; i < size-1; i++) {
x = x.next;
if(x.val == val){
return i+1;
}
}
return -1;
}
// 判断链表中是否包含值为Val值的节点
public boolean contains(int val){
if(getIndex(val) != -1){
return true;
}
return false;
}
// 修改索引为index的元素值,改为newVal返回修改前的值
public int set(int index, int newVal){
Node x = head;
int a = 0;
if(isIllegal(index)){
for (int i = 0; i < index; i++) {
x = x.next;
}
a = x.val;
x.val = newVal;
return a;
}
return -1;
}
// 删除索引为index位置的元素
public int remove(int index){
if(isIllegal(index)){
if(index == 0){
Node x = head;
head = head.next;
size--;
x.next = null;
return x.val;
}else{
Node x = head;
for (int i = 0; i < index-1; i++) {
x = x.next;
}
Node node = x.next;
x.next = node.next;
node.next = null;
size--;
return node.val;
}
}
return -1;
}
// 删除第一个值为val的元素值
public void removeValOnce(int val){
if(val == head.val){
remove(0);
}
else {
Node x = head;
while (x.next != null) {
if (x.next.val == val) {
Node node = x.next;
x.next = node.next;
node.next = null;
size--;
return;
}
x = x.next;
}
}
}
// 删除所有值为val的元素
public void removeAllVal(int val){
while (head.val == val && head != null){
Node x = head;
head = head.next;
x.next = null;
size--;
}if(head == null){
return;
}
else {
Node x = head;
while (x.next != null) {
if (x.next.val == val) {
Node node = x.next;
x.next = node.next;
node.next = null;
size--;
}else {
x = x.next;
}
}
}
}
// 打印链表
public String toString(){
String ret ="";
Node x = head;
while (x != null){
ret+=x.val;
ret+="->";
x = x.next;
}
ret+="null";
return ret;
}
// 判断index的非法问题
private boolean isAddIllegal(int index){
if(index < 0 || index > size){
return false;
}
return true;
}
private boolean isIllegal(int index){
if(index < 0 || index >= size){
return false;
}
return true;
}
注意:每当有index出现的时候都要判断index的合法性!!!
2.双向链表
定义:双向链表问题较为简单,有了尾节点以及前一个节点的指向,处理问题相对比较简单。
下面就是双向链表的具体代码:
public class DoubleLinkedList {
private DoubleNode head;
private int size;
private DoubleNode tail;
// 在头部插入新节点
public void addFirst(int val){
DoubleNode node = new DoubleNode(null,val,head);
if(tail == null){
tail = node;
}else {
head.prev = node;
}
head = node;
size ++;
}
// 尾插
public void addLast(int val){
DoubleNode node = new DoubleNode(tail,val,null);
if(tail == null){
head = node;
}
else {
tail.next = node;
}
tail = node;
size++;
}
// 删除节点
public void unlink(DoubleNode node){
DoubleNode prev = node.prev;
DoubleNode next = node.next;
if(prev == null){
head = node.next;
}else {
prev.next = next;
node.next = null;
}
if(next == null){
tail = prev;
}else {
next.prev = prev;
node.next = null;
}
size--;
}
// 查询index 位置的节点
public DoubleNode node(int index){
DoubleNode x = null;
x = head;
for (int i = 0; i < index; i++) {
x = x.next;
}
return x;
}
// 中间值插入
public void add(int index , int val){
if(index < 0 || index > size){
System.err.println("index is illegal");
}if(index == 0){
addFirst(val);
}else if(index == size){
addLast(val);
}
else {
DoubleNode prev = node(index-1);
DoubleNode next = prev.next;
DoubleNode cur = new DoubleNode(prev,val,next);
prev.next = cur;
next.prev = cur;
size++;
}
}
// 删除index位置节点
public void remove(int index){
if(index < 0 || index > size-1){
System.err.println("index is illegal");
}
DoubleNode cur = node(index);
unlink(cur);
}
// 删除头节点
public void removeFirst(){
remove(0);
}
public void removeLast(){
remove(size-1);
}
// 删除第一个为val值的节点
public void removeFirstVal(int val){
for (DoubleNode x = head; x != null ; x = x.next) {
if(x.val == val){
unlink(x);
break;
}
}
}
// 删除所有值为val的节点
public void removeAllVal(int val){
for (DoubleNode x = head; x != null ;) {
if(x.val == val){
DoubleNode next = x.next;
unlink(x);
x = next;
}else {
x = x.next;
}
}
}
// 打印双向链表
public String toString(){
String ret = "";
for(DoubleNode x = head ; x != null ; x = x.next){
ret += x.val;
ret += "->";
}
ret += null;
return ret;
}
}
class DoubleNode{
int val;
DoubleNode prev;
DoubleNode next;
public DoubleNode(){}
private DoubleNode(int val){
this.val = val;
}
public DoubleNode (DoubleNode prev , int val , DoubleNode next){
this.val = val;
this.prev = prev;
this.next = next;
}
}