数据结构:线性表
概要
线性表是一种线性结构,它是具有相同类型的n(n≥0)个数据元素组成的有限序列。本章先介绍线性表的几个基本组成部分:数组、单向链表、双向链表。
数组
数组有上界和下界,数组的元素在上下界内是连续的。
存储10,20,30,40,50的数组的示意图如下:
数组的特点是:数据是连续的;随机访问速度快。数组中稍微复杂一点的是多维数组和动态数组。对于C语言而言,多维数组本质上也是通过一维数组实现的。至于动态数组,是指数组的容量能动态增长的数组;对于C语言而言,若要提供动态数组,需要手动实现;而对于C++而言,STL提供了Vector;对于Java而言,Collection集合中提供了ArrayList和Vector。
单向链表
单向链表(单链表)是链表的一种,它由节点组成,每个节点都包含下一个节点的指针。
单链表的示意图如下:
表头为空,表头的后继节点是”节点10″(数据为10的节点),”节点10″的后继节点是”节点20″(数据为10的节点),…
单链表删除节点
删除”节点30″
删除之前:”节点20″ 的后继节点为”节点30″,而”节点30″ 的后继节点为”节点40″。
删除之后:”节点20″ 的后继节点为”节点40″。
单链表添加节点
在”节点10″与”节点20″之间添加”节点15″
添加之前:”节点10″ 的后继节点为”节点20″。
添加之后:”节点10″ 的后继节点为”节点15″,而”节点15″ 的后继节点为”节点20″。
单链表的特点是:节点的链接方向是单向的;相对于数组来说,单链表的的随机访问速度较慢,但是单链表删除/添加数据的效率很高。
双向链表
双向链表(双链表)是链表的一种。和单链表一样,双链表也是由节点组成,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
双链表的示意图如下:
表头为空,表头的后继节点为”节点10″(数据为10的节点);”节点10″的后继节点是”节点20″(数据为10的节点),”节点20″的前继节点是”节点10″;”节点20″的后继节点是”节点30″,”节点30″的前继节点是”节点20″;…;末尾节点的后继节点是表头。
双链表删除节点
删除”节点30″
删除之前:”节点20″的后继节点为”节点30″,”节点30″ 的前继节点为”节点20″。”节点30″的后继节点为”节点40″,”节点40″ 的前继节点为”节点30″。
删除之后:”节点20″的后继节点为”节点40″,”节点40″ 的前继节点为”节点20″。
双链表添加节点
在”节点10″与”节点20″之间添加”节点15″
添加之前:”节点10″的后继节点为”节点20″,”节点20″ 的前继节点为”节点10″。
添加之后:”节点10″的后继节点为”节点15″,”节点15″ 的前继节点为”节点10″。”节点15″的后继节点为”节点20″,”节点20″ 的前继节点为”节点15″。
双链表的Java实现
/** * Java 实现的双向链表。 * 注:java自带的集合包中有实现双向链表,路径是:java.util.LinkedList * * @author skywang * @date 2013/11/07 */ public class DoubleLink { // 表头 private DNode mHead; // 节点个数 private int mCount; // 双向链表“节点”对应的结构体 private class DNode { public DNode prev; public DNode next; public T value; public DNode(T value, DNode prev, DNode next) { this.value = value; this.prev = prev; this.next = next; } } // 构造函数 public DoubleLink() { // 创建“表头”。注意:表头没有存储数据! mHead = new DNode(null, null, null); mHead.prev = mHead.next = mHead; // 初始化“节点个数”为0 mCount = 0; } // 返回节点数目 public int size() { return mCount; } // 返回链表是否为空 public boolean isEmpty() { return mCount==0; } // 获取第index位置的节点 private DNode getNode(int index) { if (index=mCount) throw new IndexOutOfBoundsException(); // 正向查找 if (index <= mCount/2) { DNode node = mHead.next; for (int i=0; i<index; i++) node = node.next; return node; } // 反向查找 DNode rnode = mHead.prev; int rindex = mCount - index -1; for (int j=0; j<rindex; j++) rnode = rnode.prev; return rnode; } // 获取第index位置的节点的值 public T get(int index) { return getNode(index).value; } // 获取第1个节点的值 public T getFirst() { return getNode(0).value; } // 获取最后一个节点的值 public T getLast() { return getNode(mCount-1).value; } // 将节点插入到第index位置之前 public void insert(int index, T t) { if (index==0) { DNode node = new DNode(t, mHead, mHead.next); mHead.next.prev = node; mHead.next = node; mCount++; return ; } DNode inode = getNode(index); DNode tnode = new DNode(t, inode.prev, inode); inode.prev.next = tnode; inode.prev = tnode; mCount++; return ; } // 将节点插入第一个节点处。 public void insertFirst(T t) { insert(0, t); } // 将节点追加到链表的末尾 public void appendLast(T t) { DNode node = new DNode(t, mHead.prev, mHead); mHead.prev.next = node; mHead.prev = node; mCount++; } // 删除index位置的节点 public void del(int index) { DNode inode = getNode(index); inode.prev.next = inode.next; inode.next.prev = inode.prev; inode = null; mCount--; } // 删除第一个节点 public void deleteFirst() { del(0); } // 删除最后一个节点 public void deleteLast() { del(mCount-1); } }
觉得本文对你有帮助?请分享给更多人

wx号:gulinhai531
顾林海公众号
不定期推出优质文 章,喜欢的朋友们 给我个好看。
好文章,我 在看 :heart: