今天学习了链表的相关知识,并在此基础上写了一个自定义的双向结点类和链表类。
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的结点之间的引用链接实现的。相比于线性表顺序结构,链表比较方便插入和删除操作。
数组在定义时是在内存中开辟连续的一块区域,而链表则是不固定的,所以在访问时数组更加高效。但是数组必须在定义时就指定大小,所以很有可能造成内存的浪费。还有数组只需要在栈中分配空间,方便快捷。而链表还需要使用到堆中的空间。
下面是自定义的双向结点类
public class LLNode {
private Object obj;
private LLNode child = null;
private LLNode parent = null;
/**
* 它的构造方法
*/
public LLNode(Object obj) {
this.obj = obj;
}
public LLNode getChild() {
return child;
}
public void setChild(LLNode child) {
this.child = child;
}
public LLNode getParent() {
return parent;
}
public void setParent(LLNode parent) {
this.parent = parent;
}
public Object getObj() {
return obj;
}
}
下面是自定义的双向链表类
public class LinkList {
private static LLNode head = null;
private LLNode tail = null;
/**
* 双向链表的构造方法
*/
public LinkList() {
}
/**
* 重写构造方法,创建链表时传入根结点
*/
public LinkList(Object obj) {
head = new LLNode(obj);
tail = head;
}
/**
* 向链表最后添加元素
*
* @param obj
* 添加的元素
*/
public void add(Object obj) {
LLNode node = new LLNode(obj);
if (head == null) {
head = new LLNode(obj);
tail = head;
} else {
tail.setChild(node);
node.setParent(tail);
tail = node;
}
}
/**
* 重写添加的方法 在指定位置添加
*
* @param obj
* 添加的元素
* @param index
* 添加的位置(下标值)
*/
public void add(Object obj, int index) {
LLNode node = new LLNode(obj);
if (index < 0 || index > size()) {// 如果越界
throw new RuntimeException("越界!可添加的范围为:0~" + size() + ".");
} else if (head == null) {// 如果没有开始结点
head = node;
tail = head;
} else if (index == 0) {// 如果插入到链表开头
node.setChild(head);
head.setParent(node);
head = node;
} else if (index == size()) {// 如果插入到链表结尾
add(obj);
} else {
int i = 0;
LLNode current = head;
// 找到位置
while (i != index) {
current = current.getChild();
i++;
}
LLNode fNode = current.getParent();
fNode.setChild(node);
node.setParent(fNode);
node.setChild(current);
current.setParent(node);
}
}
/**
* 替换指定下标处得元素
* @param obj 给予替换的元素
* @param index 指定的下标
*/
public void set(Object obj, int index){
LLNode node = new LLNode(obj);
if (index < 0 || index > size()) {// 如果越界
throw new RuntimeException("越界!可添加的范围为:0~" + size() + ".");
} else if (head == null) {// 如果没有开始结点
System.out.println("没有可以替换的位置,因为它是空链表!");
} else if (index == 0) {// 如果替换到链表开头
node.setChild(head.getChild());
head.getChild().setParent(node);
head = node;
} else if (index == size()) {// 如果替换到链表结尾
node.setParent(tail.getParent());
tail.getParent().setChild(node);
tail = node;
} else {
int i = 0;
LLNode current = head;
// 找到位置
while (i != index) {
current = current.getChild();
i++;
}
LLNode pNode = current.getParent();
LLNode cNode = current.getChild();
pNode.setChild(node);
node.setParent(pNode);
node.setChild(cNode);
cNode.setParent(node);
}
}
/**
* 返回此链表中首次出现的指定元素的索引,如果此列表中不包含该元素,则返回 -1
* @param obj 指定的元素
* @return 返回此列表中首次出现的指定元素的下标值
*/
public int indexOf(Object obj){
LLNode current = head;
// 找到位置
int i;
for(i = 0;i<size();i++){
if(current.getObj() == obj){
break;
}
if(i==(size()-1)){
return -1;
}
current = current.getChild();
}
return i;
}
/**
* 移除链表中的一个结点
*
* @param obj
* 移除此元素的节点
* @return 返回表示是否移除
*/
public boolean remove(Object obj) {
LLNode current;
if (head.getObj() == obj) {
current = head.getChild();
current.setParent(null);
head = current;
return true;
} else if (tail.getObj() == obj) {
current = tail.getParent();
current.setChild(null);
tail = current;
return true;
} else {
current = head.getChild();
// 找到位置
for(int i = 0;i<size();i++){
if(current.getObj() == obj){
break;
}
if(i==(size()-1)){
return false;
}
current = current.getChild();
}
LLNode cnode = current.getChild();
LLNode pnode = current.getParent();
pnode.setChild(cnode);
cnode.setParent(pnode);
return true;
}
}
/**
* 移除链表中的一个元素,并返回它
*
* @param index
* 指定的下标位置
* @return 返回这个指定位置的元素
*/
public Object remove(int index) {
LLNode current ;
if(size() == 0){
System.out.println("链表中没有元素,无法移除!");
return null;
}else if (index < 0 || index > size()) {// 如果越界
throw new RuntimeException("越界!可移除的范围为:0~" + size() + ".");
}else if(index == 0){//如果指定位置在开头
LLNode temp = head;
current = head.getChild();
current.setParent(null);
head = current;
return temp.getObj();
}else if(index == size()){//如果指定位置在结尾
LLNode temp = tail;
current = tail.getParent();
current.setChild(null);
tail = current;
return temp.getObj();
}else{
current = head;
int i=0;
while(i != index){
i++;
current = current.getChild();
}
LLNode cnode = current.getChild();
LLNode pnode = current.getParent();
pnode.setChild(cnode);
cnode.setParent(pnode);
return current.getObj();
}
}
/**
* 移除链表中所有元素
*/
public void removeall() {
head.setChild(null);
tail.setParent(null);
head = null;
tail = head;
}
/**
* 判断链表长度的方法
*
* @return 返回链表的长度
*/
public int size() {
int i = 0;
LLNode current = head;
while (current != null) {
current = current.getChild();
i++;
}
return i;
}
/**
* 得到指定下标的元素,但不在链表中移除它
* @param index 指定的下标位置
* @return 返回该元素
*/
public Object get(int index){
if(size() == 0){
System.out.println("链表中没有元素,无法得到!");
return null;
}else if (index < 0 || index > size()) {// 如果越界
throw new RuntimeException("越界!可得到的范围为:0~" + size() + ".");
}else{
LLNode current = head;
int i=0;
while(i != index){
i++;
current = current.getChild();
}
return current.getObj();
}
}
/**
* 从此结点向下遍历的方法
*
* @param node
* 给予的起始结点
*/
public void printfromHead(LLNode node) {
if (node == null) {
System.out.println("链表为空!");
} else {
System.out.println(node.getObj());
if (node.getChild() != null) {
LLNode current = node.getChild();
printfromHead(current);
}
}
}
/**
* 从此结点向上遍历的方法
*
* @param node
* 给予的起始结点
*/
public void printfromTail(LLNode node) {
if (node == null) {
System.out.println("链表为空!");
} else {
System.out.println(node.getObj());
if (node.getParent() != null) {
LLNode current = node.getParent();
printfromTail(current);
}
}
}
/**
* 遍历打印链表的方法
*
* @param node
* 给予的起始结点
*/
public void printList(LLNode node) {
if (node == null) {
System.out.println("链表为空!");
} else {
// 开始向上遍历
if (node.getParent() != null) {
System.out.println("----开始向上遍历----");
LLNode current = node;
printfromTail(current);
} else {
System.out.println("已是根节点,无法向上遍历");
}
// 开始向下遍历
if (node.getChild() != null) {
System.out.println("----开始向下遍历----");
LLNode current = node;
printfromHead(current);
} else {
System.out.println("已是尾节点,无法向下遍历");
}
}
}
}
分享到:
相关推荐
用Java定义一个双向链表,实现链表的基本操作: 初始化、获取头结点、添加新元素、删除链表元素、 获取链表元素、查找链表元素、更新链表中某个元素、 判断链表是否为空、求链表元素个数、输出链表元素、清空链表。
JAVA实现链表_双向链表
用java实现双向链表的完整操作,主要用到内部类实现。
操作包括: 1. 在头部添加结点 2. 在尾部添加结点 3. 遍历 4. 逆置 5. 删除
通过java实现的双向链表,及反转功能,可能对面试有用哦
Java 有序 非循环 双向 链表 算法 实例
自定义的双向链表 博文链接:https://hiliangliang1130-126-com.iteye.com/blog/1144023
主要介绍了Java实现双向链表(两个版本)的相关资料,需要的朋友可以参考下
http://msdn.microsoft.com/en-us/library/95z04bas(v=VS.71).aspx 双向链表
Java算法实例-双向链表操作,封装性高,考试、学习都可使用
相信大家都明白 LinkedList 是基于双向链表而实现的,本篇文章主要讲解一下双向链表的实现,并且我们参考 LinkedList 自己实现一个单链表尝试一下。 什么是链表? 简单的来讲一下什么是链表:首先链表是一种线性的...
双端链表和双向链表Java代码
双向链表
自定义模拟LinkedList的实现!数据结构的分析,有助于喜欢研究数据结构的朋友一起探讨,qq:303651404
详细的介绍了Linux内核中使用的最频繁的双向链表
双向链表的操作问题 Time Limit: 1000MS Memory Limit: 10000KB Submissions: 111 Accepted: 41 Description 建立一个长度为n的带头结点的双向链表,使得该链表中的数据元素递增有序排列。(必须使用双向链表完成...
双向链表类定义及测试文件 对应于数据机构与算法分析(c++版)第三版或第二版 Clifford A.Shaffer 重庆大学使用教材
* 基于双向链表实现双端队列结构 */ package dsa; public class Deque_DLNode implements Deque { protected DLNode header;//指向头节点(哨兵) protected DLNode trailer;//指向尾节点(哨兵) protected ...
操作系统c++编程实现安全型双向链表,线程的创建,利用线程对链表进行增删改操作,并检验结果是否正确
使用java语言实现双向链表,提供测试用例说明功能