线性表的顺序存储结构的特点是逻辑关系上相邻的两个元素在物理位置上也相邻,因此可以随机存取表中的任意元素,它的存储位置可用一个简单的、直观的公式来表示然而,从另一方面来看,这个特点也铸成了这种结构的弱点,在做插入或删除操作时,需要大量的移动元素,那么我们来讨论一下另一种表示方法----链式存储结构,由于它不要求逻辑上相邻的元素在物理位置上也相邻,因此他没有顺序存储结构所具有的弱点,但同时也失去了顺序表可随机存取的优点.
线性链表
线性链表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的).因此为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置).这两部分信息组成数据ai的存储映像,称为节点.它包括两个域,其中存储数据元素信息的域称为数据域;存储直接后继存储位置的域成为指针域,指针域中存储的信息称作指针或链.n个节点(ai(i<=i <= n)的存储映像)链结成一个链表,即为线性表.
(a1,a2,…,an)
的链式存储结构.又由于此链表的每个节点中只包含一个指针域,故有称为线性链表或单链表;
用线性链表示线性表时,数据元素之间的逻辑关系是由节点中的指针指示的.换句话说,指针为元素之间的逻辑关系的映像,则逻辑上相邻的两个元素其存储的物理位置不要求紧邻,由此这种存储结构为非顺序映像或链式映像;
package main.com.cs.test;
public class linkList<T> {
private Node<T> head; //链表头节点
private Node<T> tail; //链表的尾节点
public linkList(){
head = tail = null;
}
private static class Node<T> {
T data;//节点数据
Node<T> next;// 下一个节点的指针
Node(T data) {
this.data = data;
this.next = null;
}
}
public void addHead(T point){
this.head = new Node<T>(point);
if (tail == null){
tail = head;
}
}
public void addTail(T point){
this.tail = new Node<T>(point);
head.next = tail;
}
public void insert(T point){
if(this.head == null){
addHead(point);
}else if (this.tail == this.head){
addTail(point);
}else {
Node<T> preNext = new Node<T>(point);
Node<T> newNode = new Node<T>(point);
preNext = head.next;
this.head.next = newNode;
newNode.next = preNext;
}
}
public void delete(T data){//删除某一节点
Node<T> curr = head, prev = null;
boolean suc = false;//是否删除成功标志
while (curr != null) {
if (curr.data.equals(data)) {
//判断是什么节点
if (curr == head) { //如果删除的是头节点
System.out.println('\n'+"delete head node");
head = curr.next;
suc = true;
return;
}
if (curr == tail) { //如果删除的是尾节点
System.out.println('\n'+"delete tail node");
tail = prev;
prev.next = null;
suc = true;
return;
} else {//如果删除的是中间节点(即非头节点或非尾节点)
System.out.println('\n'+"delete center node");
prev.next = curr.next;
suc = true;
return;
}
}
prev = curr;
curr = curr.next;
}
if(suc == false) {
System.out.println('\n'+"没有这个数据");
}
}
public void printLinkList() { //打印链表
Node<T> curr = this.head;
if (isEmpty()) {
try {
throw new Exception("linklist is empty");
} catch (Exception e) {
e.printStackTrace();
}
}
while(curr != null){
System.out.print(curr.data+" ");
curr = curr.next;
}
}
public boolean isEmpty(){//判断链表是否为空
return this.head == null || this.tail == null;
}
public static void main(String[] args) {
linkList<Integer> mylist = new linkList<Integer>();//构造一个空链表
mylist.insert(5);
mylist.insert(6);
mylist.insert(7);
mylist.insert(3);
mylist.printLinkList();
}
}
补充方法 在某个节点之后 添加一个 节点
//predata 指的是 在那个节点之后 插入节点
public void insert(T predata,T point){
//从头结点依次往下找
Node<T> curr = this.head;
if (curr == null){
throw new RuntimeException("链表为null");
}
while (curr != null){
//获取 要插入节点 的 之前的节点
if (predata == curr.data){
//构建新的节点
Node<T> newNode = new Node<T>(point);
//取当前节点的下一个节点的值
Node<T> next = curr.next;
curr.next = newNode;
newNode.next = next;
return;
}
curr = curr.next;
}
}
总结:
这里利用了面向对象的思想 ,这里首先需要构建我们的节点对象,节点对象 里面放了两个成员变量 一个是 数据 一个是 记录下一个节点(节点对象)
private static class Node<T> {
T data;//节点数据
Node<T> next;// 下一个节点的指针
Node(T data) { //赋值
this.data = data;
this.next = null;
}
}
通过这个对象那么我们 就能 得到一串的节点,修改只需找到对应的节点 修改其记录的下一个节点即可.