数据存储共有两种形式,一种是连续的,比如说数组,存储时是连续的;还有一种是离散的,这就是链表。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的引用域。 链表又分为单链表,双链表和循环链表。
我们先来看单链表,图示为:
由图我们可以看出结点左端的方格是数据域,用来存储数据,而右端是引用域,用来存储下一个节点的地址,便于我们方便的读取到。单链表的引用域是单一指向的,指向他的下一个结点。第一个结点称之为根节点,最后一个节点称之为尾结点。
循环链表是与单链表一样,是一种链式的存储结构,所不同的是,循环链表的尾结点的引用域是指向该循环链表的根节点,从而构成一个环形的链。
而双链表就比单链表方便很多,因为单链表指向是单向的,而双链表有两个引用域,一个指向前一个结点,另一个指向下一个结点。当然根节点只有指向下一个节点的引用域,而尾结点只有指向前一个的引用域。这样的话查找数据时就有两种方法,一种是从前面开始查找,一种就是从后面开始查找。
下面附上我写的双链表的代码:
结点类:
public class Node { private Object obj;// 数据域 private Node next;// 引用域 private Node prior;//引用域 public Node(Object obj) { this.obj = obj; } public Node getPrior() { return prior; } public void setPrior(Node prior) { this.prior = prior; } public Object getObj() { return obj; } public void setObj(Object obj) { this.obj = obj; } public Node getNext() { return next; } public void setNext(Node next) { this.next = next; } }
链表类:
public class LinkedList { public Node root;// 根节点 public Node endNode;// 尾节点 private int size;// 链表大小 /** * method of add node * * @param node */ public void add(Node node) { if (size == 0) { root = node; endNode = node; } else { endNode.setNext(node); node.setPrior(endNode); endNode = node; } size++; } /** * method of remove node * * @param node */ public Object removeNode(int index) { Node node = root; Node removeNode; if (index == 0) { removeNode = root; root = node.getNext(); } else { for (int i = 0; i < index - 1; i++) { node = node.getNext(); } if (index == size - 1) { removeNode = node.getNext(); node.setNext(null); } else { removeNode = node.getNext(); Node nextNode = removeNode.getNext(); node.setNext(nextNode); nextNode.setPrior(node); } } size--; return removeNode; } /** * 按正序查找指定索引位置的值 * * @param index * @return */ public Object get(int index) { if (index < 0 || index >= size) { return null; } else { Node node = root; for (int i = 0; i < index; i++) { node = node.getNext(); } return node.getObj(); } } /** * 按倒序查找指定索引位置的值 * * @param index * @return */ public Object getReverse(int index) { if (index < 0 || index >= size) { return null; } else { Node node = endNode; for (int i = size - 1; i > index; i--) { node = node.getPrior(); } return node.getObj(); } } /** * 返回链表大小的方法 * * @return */ public int size() { return size; } /** * 得到指定索引位置节点的方法 * * @param index * @return */ public Node getNode(int index) { if (index < 0 || index >= size) { return null; } else { Node node = root; for (int i = 0; i < index; i++) { node = node.getNext(); } return node; } } }
当然,链表的排序也和数组不一样,链表排序时只需改变引用域的指向,但是涉及根节点和尾结点时,要变更根结点和尾结点(将新结点设置为根结点或尾结点)。下面附上双链表的直接插入排序:
/** * 创建InsertSort类 内置直接插入排链表顺序的方法 按正序排列 * @author Administrator * */ public class InsertSort { /** * 对链表排序的方法 直接插入排序 * @param list */ public void InsertSort(LinkedList list) { int i, j; for (i = 0; i < list.size(); i++) { Node temp = list.getNode(i); for (j = i; j > 0 && Double.parseDouble(temp.getObj().toString()) < Double//将链表节点所存的object型数据转换为double型 便于比较 .parseDouble(list.getNode(j - 1).getObj() .toString()); j--) { if (j == 1) {//排前两个的顺序 //当根节点数据大于它下一个节点的的数据的时候 //改变这两个节点的指针指向 并将第二个节点设置为根节点 Node node1 = list.getNode(j - 1); Node node2 = node1.getNext(); Node node3 = node2.getNext(); node2.setNext(node1); node1.setPrior(node2); node1.setNext(node3); node3.setPrior(node1); list.root = node2; } else if (j == list.size() - 1) {//排序最后两个节点数据 同样是改变指针指向 Node node1 = list.getNode(j - 1); Node node2 = node1.getNext(); Node node3 = node1.getPrior(); node3.setNext(node2); node2.setPrior(node3); node2.setNext(node1); node1.setPrior(node2); list.endNode = node1; } else {//排序中间节点数据的方法 改变节点指针指向即可 Node node1 = list.getNode(j - 1); Node node2 = node1.getNext(); Node node3 = node2.getNext(); Node node4 = node1.getPrior(); node4.setNext(node2); node2.setPrior(node4); node2.setNext(node1); node1.setPrior(node2); node1.setNext(node3); node3.setPrior(node1); } } } } }
备注:图片来自于360百科
相关推荐
本教程将通过两个经典示例深入讲解如何在C语言中使用链表。 首先,我们来看第一个示例——"Demo1.c"。在这个示例中,我们将创建一个表示学生成绩的链表,每个节点包含学生的ID和分数。为了实现这个链表,我们需要...
总结来说,这个C++链表教程涵盖了链表的基本概念、数据结构定义、操作符重载以及常见的链表操作函数实现,这些都是理解和使用链表的关键知识。通过这些内容,开发者可以有效地在C++中构建和管理链表数据结构,进行...
双向链表使用说明.txt
使用 python3 实现一个链表 使用 python3 实现一个链表 使用 python3 实现一个链表 使用 python3 实现一个链表 使用 python3 实现一个链表 使用 python3 实现一个链表 使用 python3 实现一个链表 使用 python3 实现...
数据结构学习辅助,链表使用例程,注释非常清楚,而且可以实际运行,方便初学者调试、体会
将linux内核源码中list.h拿出来, 增删与遍历部分写了详细注释, 关于链表合并, 没用过所以没写. 源码版本是2.6.32, 不过链表的源码改动应该不是很大. 我的邮箱2253238252@qq.com, 代码有什么不对的欢迎发邮件给我
在本文中,我们将深入探讨如何使用C++实现双向循环链表。双向循环链表是一种特殊的数据结构,每个节点不仅包含数据,还包含两个指针,分别指向前一个节点和后一个节点,形成一个首尾相接的循环链。这种数据结构在...
链表使用引用来定位元素,时间复杂度为O(n)。这也就是为什么数组的访问速度比链表快的原因。 5. 插入和删除操作 数组插入或删除元素的时间复杂度为O(n),因为需要移动所有元素的位置。链表插入或删除元素的时间...
链表使用指针来指向下一个节点,这可以导致指针的使用不当。 ### 实现的复杂性 链表的实现可以很复杂,需要考虑节点的管理、内存的分配等问题。 数组与链表的对比 ------------------- 数组和链表是两种常用的...
3. 节点号排序:这通常涉及到对链表的遍历,可以使用各种排序算法,如冒泡排序、选择排序或更高效的快速排序、归并排序等。在这个实例中,可能根据图书的编号进行排序。 4. 节点搜索:查找链表中特定值的节点,通常...
这些扩展都是基于基础的`list`结构,增加了链表使用的灵活性和效率。 在实际应用中,比如在网络过滤框架Netfilter中,使用链表来组织协议族的`nf_sockopt_ops`结构,每个结构都有一个`struct list_head list`成员,...
- **链表的动态内存管理**:链表使用`malloc`动态分配内存,当链表不再需要时,应使用`free`释放已分配的内存,防止内存泄漏。 - **异常处理**:在实际编程中,应添加输入验证和错误处理机制,确保输入的有效性和...
在实际开发中,为了提高效率,可以考虑使用哈希表或二叉搜索树等数据结构配合链表使用。例如,可以建立一个哈希表,键为学号,值为指向链表中对应节点的指针,这样可以在常数时间内完成查找和删除操作。 链表在人工...
动态链表使用完毕后,需要释放每个节点占用的内存空间,避免内存泄漏。 ```c void freeList(struct Car *head) { struct Car *p = head; while (p != NULL) { struct Car *temp = p; p = p->next; free...
数组和链表的使用场景 在计算机科学中,数组和链表是两种基本的数据结构,它们都是线性表的实现方式,但它们有着不同的存储结构和访问方式,从而导致不同的使用场景。 数组是一种连续存储的数据结构,即在内存中...
在这个课程设计中,我们将探讨如何使用链表来实现信息管理,包括增加、删除和显示链表中的节点。 链表的基本概念: 链表不同于数组,它不是在内存中连续分配空间,而是由一系列分散的节点组成,每个节点包含数据和...
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:...
对于初学者来说,这是一份很好的学习资料,能够帮助他们理解链表的工作原理,以及如何在实际编程中使用链表。通过阅读和分析代码,可以加深对链表数据结构的理解,并掌握其在不同场景下的应用。同时,还可以学习如何...
封装了链表的操作,功能有链表的创建,节点的添加(附加),插入(前插、后插和插入到链表头部),删除,得到节点数据,得到节点位置,得到节点总数,释放链表。 使用了类模版,使得可以让节点中的数据为任意类型,...