链表
1、链表的基本概念
1、链表一般分为:
- 单向链表
- 双向链表
- 环形链表
2、基本概念
-
链表实际上是线性表的链式存储结构,与数组不同的是,它是用一组任意的存储单元来存储线性表中的数据,存储单元不一定是连续的,
-
链表的长度不是固定的,链表数据的这一特点使其可以非常的方便地实现节点的插入和删除操作
-
链表的每个元素称为一个节点,每个节点都可以存储在内存中的不同的位置,为了表示每个元素与后继元素的逻辑关系,以便构成“一个节点链着一个节点”的链式存储结构,
-
除了存储元素本身的信息外,还要存储其直接后继信息,因此,每个节点都包含两个部分,第一部分称为链表的数据区域,用于存储元素本身的数据信息,这里用data表示,
-
它不局限于一个成员数据,也可是多个成员数据,第二部分是一个结构体指针,称为链表的指针域,用于存储其直接后继的节点信息,这里用next表示,
创建链表节点:
public class Node {
//当前节点元素
int data;
//下一个节点
Node next;
public Node(int data) {
this.data = data;
}
public Node() {
}
}
像上面这种只包含一个指针域、由n个节点链接形成的链表,就称为线型链表或者单向链表,链表只能顺序访问,不能随机访问,链表这种存储方式最大缺点就是容易出现断链,
一旦链表中某个节点的指针域数据丢失,那么意味着将无法找到下一个节点,该节点后面的数据将全部丢失.
2、单向链表的建立和基本功能
public class LinkedNode {
private Node head; //头结点
private int size; //链表元素个数
/**
* 向头节点插入元素
* @param t
*/
private void addFirst(int t) {
Node node = new Node(t);
node.next = head; //令插入节点的下一个节点指向头节点
head = node; //令插入的节点为头节点
size++;
}
/**
* 向链表中间插入元素
*/
public void add(int t,int index){
if (index <0 || index >size){
throw new IllegalArgumentException("index is error");
}
if (index == 0){
this.addFirst(t);
return;
}
//定义临时变量存储头节点
Node preNode = this.head;
//找到要插入节点的前一个节点
for(int i = 0; i < index-1; i++){
preNode = preNode.next;
}
Node node = new Node(t);
//要插入的节点的下一个节点指向preNode的下一个节点
node.next = preNode.next;
//preNode的下一个节点指向要插入节点node
preNode.next = node;
this.size++;
}
/**
* 向链表最后添加元素
*/
public void add(int value){
add(value, this.size);
}
/**
* 获取元素的索引
* @param value
* @return
*/
public int indexOf(int value) {
int count = 0;
if (head.data == value) {
return 0;
}
Node cur = head;
while (cur != null) {
if (cur.data != value) {
count++;
cur = cur.next;
} else {
return count;
}
}
return -1;
}
/**
* 是否包含某个元素
* @param value
* @return
*/
public boolean contains(int value) {
return indexOf(value) != -1;
}
/**
* 获取指定索引位置的元素
* @param index
* @return
*/
public int get(int index) {
if (index <0 || index >size){
throw new IllegalArgumentException("index is error");
}
if (index == 0){
return head.data;
}
Node node = head;
if (index < (size >> 1)) {
for (int i = 0; i < index; i++) {
node = node.next;
}
return node.data;
}else{
for (int i = index; i < size-1; i--){
node = node.next;
}
return node.data;
}
}
/**
* 删除链表元素
*/
public void remove(int t){
if(head == null){
System.out.println("无元素可删除");
return;
}
//要删除的元素与头结点的元素相同
while(head != null && head.data == t){
head = head.next;
this.size--;
}
/**
* 上面已经对头节点判别是否要进行删除
* 所以要对头结点的下一个结点进行判别
*/
Node cur = this.head;
while(cur != null && cur.next != null){
if(cur.next.data == t){
this.size--;
cur.next = cur.next.next;
}
else cur = cur.next;
}
}
/**
* 链表长度
* @return
*/
public int size(){
return this.size;
}
/**
* 打印链表
* @return
*/
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
Node cur = this.head;
while(cur != null){
sb.append(cur.data+"->");
cur = cur.next;
}
sb.delete(sb.length()-2,sb.length());
return sb.toString();
}
}
测试
建立测试类:
public class Test {
public static void main(String[] args) {
LinkedNode node = new LinkedNode();
node.add(1);
node.add(2);
node.add(3);
node.add(4);
node.add(5);
node.add(6);
System.out.println(node.toString());
System.out.println("查找元素为2的索引:"+node.indexOf(2));
System.out.println("查找元素为9的索引:"+node.indexOf(9));
System.out.println("链表大小:"+node.size());
System.out.println("索引值为2的元素是:"+node.get(2));
node.remove(6);
System.out.println("删除后的链表:"+node.toString());
}
}
运行结果如下: