链表是非连续、无顺序的数据结构,链表中元素与元素之间的内存地址没有顺序关系。链表由一个个结点组成,结点中存储两类信息,第一类是存储入结点的数据,第二类是结点的指向。链表分为单项链表,双向链表,环形链表,单项链表中只有一个结点指向,指向的的下一个结点的内存地址,只能单向移动,单项操作;双向链表有两个结点指向,一个指向上一个结点的内存地址(父结点),另一个指向下一个结点的内存地址(子结点),可以双向运动,双向操作;环形链表其实是双向链表的首位结点相连。
对于链表,其好处是可以避免浪费内存空间,节省内存资源,不想数组定长会不可避免的浪费内存空间,不可以连续读取,连续操作,但是其大小可以动态改变。
/**
* 双向列表结点类
* @author lenovo
*
*/
public class LinkNode {
private Object obj;
private LinkNode child; //子类结点
private LinkNode parent;//父类结点
/**
* 创建有参的 构造方法
* @param obj
*/
public LinkNode(Object obj){
this.obj=obj;
}
public LinkNode(){
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public LinkNode getChild() {
return child;
}
public void setChild(LinkNode child) {
this.child = child;
}
public LinkNode getParent() {
return parent;
}
public void setParent(LinkNode parent) {
this.parent = parent;
}
}
/**
* 实现双向链表的方法类
*
* @author lenovo
*
*/
public class LinkList {
private static LinkNode head = null; // 头结点
private LinkNode foot = head; // 尾结点
// public static void main(String args[]) {
//
// LinkList list = new LinkList();
//
// list.add("新来的元素yes");
//
// // 加入结点
// for (int i = 0; i < 10; i++) {
// list.add("链表元素" + i);
// }
//
// list.set("XXX", 8);
//
// // 根据索引插入结点
// // list.add("插入的", 8);
//
// list.add("新来的元素");
// list.add("新来的元素2");
//
// // 根据索引删除结点
// list.remove("新来的元素");
//
// // 清空链表
// list.clear();
//
// // 打印链表
// list.printList(head);
//
// // 得到链表的长度
// int len = list.size();
// System.out.println("长度:" + len);
//
// LinkNode temp = list.get(1); // 根据索引得到结点并打印
// list.printList(temp);
//
// }
/**
* 添加元素的方法
*
* @param obj
* :添加的元素
*/
public void add(Object obj) {
LinkNode root = new LinkNode(obj);
// 判断链表是否为空
if (head == null) {
head = root;
foot = root;
} else {
foot.setChild(root);
root.setParent(foot);
// 为节点变为root
foot = root;
}
}
/**
* 插入元素的方法
*
* @param obj
* :插入的元素
* @param index
* :要插入的索引
*/
public void add(Object obj, int index) {
LinkNode root = new LinkNode(obj);
if (index > size() || index < 0) {
throw new RuntimeException("下标越界:" + index + ",size:" + size());
} else {
if (index == 0) { // 如果在第一个索引处插入
head.setParent(root);
root.setChild(head);
head = root;
} else if (index > 0 && index < size()) {
int count = 0; // 计数器
LinkNode n = head.getChild();
while (index != count + 1) { // 得到想要插入处原来的结点
n = n.getChild();
count++;
}
LinkNode m = n.getParent();
// 设置新的关系
m.setChild(root);
root.setParent(m);
root.setChild(n);
n.setParent(root);
} else if (index == size()) { // 如果在结尾处插入
add(obj);
}
}
}
/**
* 根据索引得到结点
*
* @param index
* :索引
* @return
*/
public LinkNode get(int index) {
if (index > size() || index < 0) {
throw new RuntimeException("下标越界:" + index + ",size:" + size());
} else {
int count = 0; // 定义计数器
LinkNode root = head;
while (count != index) { // 循环得到结点
root = root.getChild();
count++;
}
return root;
}
}
/**
* 根据索引删除结点
*
* @param index
*/
public void remove(int index) {
if (index > size() || index < 0) {
throw new RuntimeException("下标越界:" + index + ",size:" + size());
} else {
// 得到指定索引的结点
LinkNode root = this.get(index);
// 得到结点的父结点
LinkNode proot = root.getParent();
// 得到结点的子结点
LinkNode croot = root.getChild();
if (proot == null) { // 如果是第一索引的结点
head = croot;
} else if (croot == null) { // 如果是最后索引的结点
proot.setChild(null);
} else {
proot.setChild(croot);
croot.setParent(proot);
}
}
}
/**
* 根据元素删除结点
*
* @param obj
*/
public void remove(Object obj) {
LinkNode root;
if (head == null) {
throw new RuntimeException("链表为空");
}
if (head.getObj() == obj) { // 如果是头结点
root = head.getChild();
root.setParent(null);
head = root;
return;
} else if (foot.getObj() == obj) { // 如果是尾结点
root = foot.getParent();
root.setChild(null);
foot = root;
return;
} else {
root = head.getChild();
for (int i = 0; i < size(); i++) {
if (root.getObj() == obj) {
remove(i + 1); // 从1的索引开始遍历
return;
}
root = root.getChild();
}
}
}
/**
* 替换链表上相应索引结点的方法
*
* @param obj
* @param index
*/
public void set(Object obj, int index) {
if (index < 0 || index > size()) {
throw new RuntimeException("下标越界:" + index + ",size:" + size());
}
remove(index);
add(obj, index);
}
/**
* 统计链表长度的方法
*
* @return
*/
public int size() {
LinkNode root = new LinkNode(); // 创建一个LinkNode对象,开辟内存空间
root = head;
// 定义一个计数器
int count = 0;
while (root != null) {
count++;
root = root.getChild();
}
return count;
}
/**
* 清空链表的方法
*/
public void clear() {
head.setChild(null);
foot.setParent(null);
head = null;
foot = head;
}
/**
* 遍历列表
*
* @param root
*/
public void printList(LinkNode root) {
if (root != null) {
Object obj = root.getObj();
System.out.println(obj);
if (root.getChild() != null) {
printList(root.getChild()); // 递归调用
}
}
}
}
分享到:
相关推荐
delphi自定义链表实例.rar`
完成学生信息管理系统的设计与实现,数据存储使用自定义链表,实现赠、删、查、改的功能。执行界面如下: 系统界面: *********************学生基本信息管理系统********************* ****1、添加 2、查询 ****...
自实现链表 还非得大于20字,那我就写点废话,把这个字数凑够,应该够了吧
java基础知识代码实现,包括冒泡算法,快速算法,九九乘法表,创建多线程的方式,自定义链表,递归使用方式,创建单例等,可解压代码直接运行测试学习!
单向动态链表的建立,及修改!
是用数据结构和算法中链表的算法,来设计有界面的链表运用的实例。 是用数据结构和算法中链表的算法,来设计有界面的链表运用的实例。
C++的模版类,实现了链表的基本功能,添删改查。
java 自定义链表的使用,仅供参考,自定义使用
使用链表; 编写自定义链表存储目标 ;设计存储学生基本信息机构体;实现用链表形式对多名学生信息的存储和访问;以控制台输出练习结果
猴子选大王 1. 题目要求: 任务:一堆猴子都有编号,编号是1,2,3 ...m ,这群猴子(m 个)按照1-m的顺序围坐一圈,从第1开始数,每数到第N个,该猴子就 ...//自定义链表类型 ListNode *q,*p; Linklist head=(Linklist
自定义模拟LinkedList的实现!数据结构的分析,有助于喜欢研究数据结构的朋友一起探讨,qq:303651404
数据结构课程设计,程序实现是基于C++且无图形界面 ... 核心算法是拓扑排序,图的存储形式是邻接数组,使用了自定义链表类型队列来完成拓扑排序时得候选容器与结果容器。输出结果方案文件在项目文件中
链表实现大数阶乘方便初学者使用!使用的是自定义链表类,方便大家使用
本篇文章是对c#中自定义泛型链表类进行了详细的分析介绍,需要的朋友参考下
C#如何自定义线性节点链表集合,这篇文章主要为大家详细介绍了C#基于泛型的自定义线性节点链表集合示例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
C 程序设计:7 自定义数据类型-链表.ppt
多边形扫描转换因采用链表结构而使程序简洁、快速...根据相关文献的算法,分另q写出了采用自定义链表方式和使用链表模板方式实现多边形扫描转换的完整C++程序。实例对比表明,采用标准模板库使程序调试方便和运行稳定。
java双端队列的实现-Java实现自定义双端队列(链表和数组两种方式) 数组和链表.pdf