前言
前面我们学习了顺序表,了解到了顺序表的操作方便,也便于理解,但顺序表也有缺点,比如在插入或者删除结点的时候,需要移动大量的数据,如果表比较大,有时还难以分配足够的连续的存储空间,往往导致内存分配失败,这也是这里我们为什么学习链表结构的原因
引入
链表结构,一种动态存储分配的结构,可以根据需要动态申请内存单元,在逻辑上相邻的结点在物理内存上不一定相邻
链表结构的缺点
* 浪费存储空间
* 顺序访问,访问效率较低
* 空间密度不高
所以一般查找频繁的使用表都是采用顺序表,修改操作频繁的使用链表
链表的种类
单链表:链式结构,每个节点只包含一个引用
双向链表:若每个节点包含俩个引用,一个指向下一个结点,另一个指向上一个结点
单循环链表:在单链表中,将终端结点的引用域 null 改为指向表头结点或开始结点即可构成
多重链的循环链表:将表中结点链在多个环上
大家可以了解一下以上的各种表,本文只跟大家演示单链表,接下来我们看代码具体实现
package List;
import java.util.Scanner;
/**
*@author Mr.wei
*@version 1.0
*/
public class LinkList {
static class DATA{
String key;
String name;
int age;
}
//定义链表结构
static class CLType{
DATA nodeData = new DATA();
CLType nextNode;
//插入头结点,头插法
CLType CLAddFirst(CLType head,DATA nodeData)
{
CLType node = new CLType();
if( node == null ){
System.out.println("申请内存失败!\n");
return null;
}else{
node.nodeData = nodeData;//保存数据
node.nextNode = head;
head = node;
return head;
}
}
//插入尾结点,
CLType CLAddend(CLType head,DATA nodeData){
CLType node,temp;
node = new CLType();
if(node == null){
System.out.println("内存申请失败");
return null;
}else{
node.nodeData = nodeData;
node.nextNode = null;//设置结点引用为空,即为表尾
if(head == null){
head = node;
return head;
}
temp = head;
while( temp.nextNode != null){
temp = temp.nextNode;//temp 不为空继续追溯到下一结点,直到为空即是表尾
}
temp.nextNode = node;//将node作为新的表尾
return head;
}
}
//查找结点
CLType CLFind(CLType head,String key){
CLType temp;
temp = head;
while(temp != null){
if(temp.nodeData.key.equals(key)){//找到结点返回
return temp;
}
temp = temp.nextNode;
}
return null;//没有找到返回空
}
//插入结点
CLType CLinsert(CLType head,String key,DATA nodeData){
CLType nodetemp = CLFind(head, key);//查找要插入的结点位置
CLType node;//接收待插入结点
if( (node = new CLType()) == null){
System.out.println("申请内存失败");
}
node.nodeData = nodeData;
if(nodetemp != null){
node.nextNode = nodetemp.nextNode;
nodetemp.nextNode = node.nextNode;
}
else{
System.out.println("找不到正确的插入位置");
}
return head;
}
//删除结点
int CLdelete(CLType head,String key){
CLType node,temp;
temp = head;
node = head;
while(temp != null){
if(temp.nodeData.key.compareTo(key) == 0){//找到学号执行删除操作
node.nextNode = temp.nextNode;
temp = null;
return 1;
}
else{
node = temp;
temp = temp.nextNode;
}
}
return 0;
}
//得到链表长度
int CLength(CLType head){
CLType temp = head;
int i = 0;
while(temp != null){
i++;
temp = temp.nextNode;
}
return i;
}
//遍历所有结点
void CLALL(CLType head){
CLType temp;
DATA nodeData;
temp = head;
while(temp != null){
nodeData = temp.nodeData;
System.out.printf("结点为%s,%s,%d\n",nodeData.key,nodeData.name,nodeData.age);
temp = temp.nextNode;
}
}
}
public static void main(String[] args) {
CLType node,head = null;
CLType CL = new CLType();
String key,findkey;
Scanner input = new Scanner(System.in);
System.out.println("请输入链表中的数据,格式为:学号,姓名,年龄(以0结束)");
do{
DATA nodeData = new DATA();
nodeData.key = input.next();
if(nodeData.key.equals("0")){
break;
}
else{
nodeData.name = input.next();
nodeData.age = input.nextInt();
head = CL.CLAddend(head, nodeData);
//head = CL.CLAddFirst(head, nodeData);
}
}while(true);
//遍历
CL.CLALL(head);
System.out.println("请输入要查找的结点(输入学号)");
findkey = input.next();
System.out.println("该学号的名字为"+CL.CLFind(head, findkey).nodeData.name);
//删除结点
System.out.println("请输入要删除的学号:");
findkey = input.next();
CL.CLdelete(head, findkey);
CL.CLALL(head);
//得到表长
System.out.println("表长为"+CL.CLength(head));
}
}
代码运行结果