《数据结构》线性表——链式存储结构
线性表链式存储结构简称链表,与顺序不同的是链表中的结点不仅包含有元素本身的信息,还包含有元素之间的逻辑关系的信息!!!
注意:在java中不存在指针的概念,这里的指针成员实际上存放的是后继结点或者前驱结点的引用!
目录
一、链表的介绍
二、构建单链表
1、单链表泛型类:
2、头插法建表
3、尾插法建表
4、在线性表的末尾添加一个元素e
5、求线性表长度
6、设置线性表的长度
7、返回线性表中序号为i的元素
8、设置序号i的元素为e
9、查找第一个为e的元素的序号
10、交换序号i和序号j的元素
11、在线性表中序号i位置插入元素e
12、在线性表中删除序号i位置的元素
13、将线性表转换为字符串
14、单链表完整代码
三、构建双链表
1、双链表结点泛型类
2、头插法建表
3、尾插法建表
4、在线性表的末尾添加一个元素e
5、求线性表长度
6、设置线性表的长度
7、返回线性表中序号为i的元素
8、设置序号i的元素为e
9、查找第一个为e的元素的序号
10、在线性表中序号i位置插入元素e
11、在线性表中删除序号i位置的元素
12、将线性表转换为字符串
13、双链表完整代码
一、链表的介绍
链表分为两种,一种是单链表,另一个是双链表。
- 单链表:每个结点只设置一个指向其后继结点的指针成员。
- 双链表:每个结点中只设置两个指针成员,分别用于指向其前驱结点和后继结点。
(a)单链表
(b) 双链表
双链表中的头结点不存放任何数据元素(空表是仅包含头结点的链表),存放序号为0的元素的结点称为开始结点或者首结点,存放终端元素的结点称为终端结点或者尾结点。
一般链表的长度不计头结点,仅仅指其中数据结点的个数。
由上图可以看出,其实链表的逻辑结构就像一串珠子,我们可以这么来理解,容易记忆!
图片来源于百度,侵删!
二、构建单链表
1、单链表泛型类:
class LinkNode<E> //单链表结点泛型类
{E data;LinkNode<E> next;public LinkNode() { //构造方法next=null;}public LinkNode(E d) //重载构造方法{data=d;next=null;}
}public class LinkListClass<E> //单链表泛型类
{LinkNode<E> head; //存放头结点public LinkListClass() //构造方法{head=new LinkNode<E>(); //创建头结点head.next=null;}private LinkNode<E> geti(int i) //返回序号为i的结点{LinkNode<E> p=head;int j=-1;while (j<i){j++;p=p.next;}return p;}//线性表的基本运算算法
}
2、头插法建表
public void CreateListF(E[] a) //头插法:由数组a整体建立单链表{LinkNode<E> s;for (int i=0;i<a.length;i++) //循环建立数据结点s{s=new LinkNode<E>(a[i]); //新建存放a[i]元素的结点ss.next=head.next; //将s结点插入到开始结点之前,头结点之后head.next=s;}}
3、尾插法建表
public void CreateListR(E[] a) //尾插法:由数组a整体建立单链表{LinkNode<E> s,t;t=head; //t始终指向尾结点,开始时指向头结点for (int i=0;i<a.length;i++) { //循环建立数据结点ss=new LinkNode<E>(a[i]); //新建存放a[i]元素的结点st.next=s; //将s结点插入t结点之后t=s;}t.next=null; //将尾结点的next字段置为null}
4、在线性表的末尾添加一个元素e
public void Add(E e) //在线性表的末尾添加一个元素e{LinkNode<E> s=new LinkNode<E>(e); //新建结点sLinkNode<E> p=head;while (p.next!=null) //查找尾结点pp=p.next;p.next=s; //在尾结点之后插入结点s}
5、求线性表长度
public int size() //求线性表长度{LinkNode<E> p=head;int cnt=0;while (p.next!=null) //找到尾结点为止{cnt++;p=p.next;}return cnt;}
6、设置线性表的长度
public void Setsize(int nlen) //设置线性表的长度{int len=size();if (nlen<0 || nlen>len)throw new IllegalArgumentException("设置长度:n不在有效范围内");if (nlen==len) return;LinkNode<E> p=geti(nlen-1); //找到序号为nlen-1的结点pp.next=null; //将结点p置为尾结点}
7、返回线性表中序号为i的元素
public E GetElem(int i) //返回线性表中序号为i的元素{int len=size();if (i<0 || i>len-1)throw new IllegalArgumentException("查找:位置i不在有效范围内");LinkNode<E> p=geti(i); //找到序号为i的结点preturn (E)p.data;}
8、设置序号i的元素为e
public void SetElem(int i,E e) //设置序号i的元素为e{if (i<0 || i>size()-1)throw new IllegalArgumentException("设置:位置i不在有效范围内");LinkNode<E> p=geti(i); //找到序号为i的结点pp.data=e;}
9、查找第一个为e的元素的序号
public int GetNo(E e) //查找第一个为e的元素的序号{int j=0;LinkNode<E> p=head.next; while (p!=null && !p.data.equals(e)){j++; //查找元素ep=p.next;}if (p==null) //未找到时返回-1return -1;elsereturn j; //找到后返回其序号}
10、交换序号i和序号j的元素
public void swap(int i,int j) //交换序号i和序号j的元素{LinkNode<E> p=geti(i);LinkNode<E> q=geti(j);E tmp=p.data;p.data=q.data;q.data=tmp;}
11、在线性表中序号i位置插入元素e
public void Insert(int i, E e) //在线性表中序号i位置插入元素e{if (i<0 || i>size()) //参数错误抛出异常throw new IllegalArgumentException("插入:位置i不在有效范围内");LinkNode<E> s=new LinkNode<E>(e); //建立新结点s LinkNode<E> p=head=geti(i-1); //找到序号为i-1的结点ps.next=p.next; //在p结点后面插入s结点p.next=s;}
12、在线性表中删除序号i位置的元素
public void Delete(int i) //在线性表中删除序号i位置的元素{if (i<0 || i>size()-1) //参数错误抛出异常throw new IllegalArgumentException("删除:位置i不在有效范围内");LinkNode<E> p=geti(i-1); //找到序号为i-1的结点pp.next=p.next.next; //删除p结点的后继结点}
13、将线性表转换为字符串
public String toString() //将线性表转换为字符串{String ans="";LinkNode<E> p=head.next;while (p!=null){ans+=p.data+" ";p=p.next;}return ans;}
14、单链表完整代码
import java.util.*;
@SuppressWarnings("unchecked")
class LinkNode<E> //单链表结点泛型类
{E data;LinkNode<E> next;public LinkNode() { //构造方法next=null;}public LinkNode(E d) //重载构造方法{data=d;next=null;}
}public class LinkListClass<E> //单链表泛型类
{LinkNode<E> head; //存放头结点public LinkListClass() //构造方法{head=new LinkNode<E>(); //创建头结点head.next=null;}private LinkNode<E> geti(int i) //返回序号为i的结点{LinkNode<E> p=head;int j=-1;while (j<i){j++;p=p.next;}return p;}//线性表的基本运算算法 public void CreateListF(E[] a) //头插法:由数组a整体建立单链表{LinkNode<E> s;for (int i=0;i<a.length;i++) //循环建立数据结点s{s=new LinkNode<E>(a[i]); //新建存放a[i]元素的结点ss.next=head.next; //将s结点插入到开始结点之前,头结点之后head.next=s;}}public void CreateListR(E[] a) //尾插法:由数组a整体建立单链表{LinkNode<E> s,t;t=head; //t始终指向尾结点,开始时指向头结点for (int i=0;i<a.length;i++) { //循环建立数据结点ss=new LinkNode<E>(a[i]); //新建存放a[i]元素的结点st.next=s; //将s结点插入t结点之后t=s;}t.next=null; //将尾结点的next字段置为null}public void Add(E e) //在线性表的末尾添加一个元素e{LinkNode<E> s=new LinkNode<E>(e); //新建结点sLinkNode<E> p=head;while (p.next!=null) //查找尾结点pp=p.next;p.next=s; //在尾结点之后插入结点s}public int size() //求线性表长度{LinkNode<E> p=head;int cnt=0;while (p.next!=null) //找到尾结点为止{cnt++;p=p.next;}return cnt;}public void Setsize(int nlen) //设置线性表的长度{int len=size();if (nlen<0 || nlen>len)throw new IllegalArgumentException("设置长度:n不在有效范围内");if (nlen==len) return;LinkNode<E> p=geti(nlen-1); //找到序号为nlen-1的结点pp.next=null; //将结点p置为尾结点}public E GetElem(int i) //返回线性表中序号为i的元素{int len=size();if (i<0 || i>len-1)throw new IllegalArgumentException("查找:位置i不在有效范围内");LinkNode<E> p=geti(i); //找到序号为i的结点preturn (E)p.data;}public void SetElem(int i,E e) //设置序号i的元素为e{if (i<0 || i>size()-1)throw new IllegalArgumentException("设置:位置i不在有效范围内");LinkNode<E> p=geti(i); //找到序号为i的结点pp.data=e;}public int GetNo(E e) //查找第一个为e的元素的序号{int j=0;LinkNode<E> p=head.next; while (p!=null && !p.data.equals(e)){j++; //查找元素ep=p.next;}if (p==null) //未找到时返回-1return -1;elsereturn j; //找到后返回其序号}public void swap(int i,int j) //交换序号i和序号j的元素{LinkNode<E> p=geti(i);LinkNode<E> q=geti(j);E tmp=p.data;p.data=q.data;q.data=tmp;} public void Insert(int i, E e) //在线性表中序号i位置插入元素e{if (i<0 || i>size()) //参数错误抛出异常throw new IllegalArgumentException("插入:位置i不在有效范围内");LinkNode<E> s=new LinkNode<E>(e); //建立新结点s LinkNode<E> p=head=geti(i-1); //找到序号为i-1的结点ps.next=p.next; //在p结点后面插入s结点p.next=s;}public void Delete(int i) //在线性表中删除序号i位置的元素{if (i<0 || i>size()-1) //参数错误抛出异常throw new IllegalArgumentException("删除:位置i不在有效范围内");LinkNode<E> p=geti(i-1); //找到序号为i-1的结点pp.next=p.next.next; //删除p结点的后继结点}public String toString() //将线性表转换为字符串{String ans="";LinkNode<E> p=head.next;while (p!=null){ans+=p.data+" ";p=p.next;}return ans;}
}
三、构建双链表
1、双链表结点泛型类
class DLinkNode<E> //双链表结点泛型类
{E data;DLinkNode<E> prior; //前驱结点指针DLinkNode<E> next; //后继结点指针public DLinkNode() //构造方法{ prior=null;next=null;}public DLinkNode(E d) //重载构造方法{data=d;prior=null;next=null;}
}public class DLinkListClass<E> //双链表泛型类
{DLinkNode<E> dhead; //存放头结点public DLinkListClass() //构造方法{dhead=new DLinkNode<E>(); //创建头结点dhead.prior=null;dhead.next=null;}private DLinkNode<E> geti(int i) //返回序号为i的结点{DLinkNode<E> p=dhead;int j=-1;while (j<i){j++;p=p.next;}return p;}//线性表的基本运算算法
}
2、头插法建表
public void CreateListF(E[] a) //头插法:由数组a整体建立双链表{DLinkNode<E> s;for (int i=0;i<a.length;i++) //循环建立数据结点s{s=new DLinkNode<E>(a[i]); //新建存放a[i]元素的结点s,将其插入到表头s.next=dhead.next; //修改s结点的next字段if (dhead.next!=null) //修改头结点的非空后继结点的prior字段dhead.next.prior=s;dhead.next=s; //修改头结点的next字段s.prior=dhead; //修改s结点的prior字段}}
3、尾插法建表
public void CreateListR(E[] a) //尾插法:由数组a整体建立双链表{DLinkNode<E> s,t;t=dhead; //t始终指向尾结点,开始时指向头结点for (int i=0;i<a.length;i++) //循环建立数据结点s{ s=new DLinkNode<E>(a[i]); //新建存放a[i]元素的结点st.next=s; //将s结点插入t结点之后s.prior=t; t=s;}t.next=null; //将尾结点的next字段置为null}
4、在线性表的末尾添加一个元素e
public void Add(E e) //在线性表的末尾添加一个元素e{DLinkNode<E> s=new DLinkNode<E>(e); //新建结点sDLinkNode<E> p=dhead;while (p.next!=null) //查找尾结点pp=p.next;p.next=s; //在尾结点之后插入结点ss.prior=p;}
5、求线性表长度
public int size() //求线性表长度{DLinkNode<E> p=dhead;int cnt=0;while (p.next!=null) //找到尾结点为止{cnt++;p=p.next;}return cnt;}
6、设置线性表的长度
public void Setsize(int nlen) //设置线性表的长度{int len=size();if (nlen<0 || nlen>len)throw new IllegalArgumentException("设置长度:n不在有效范围内");if (nlen==len) return;DLinkNode<E> p=geti(nlen-1); //找到序号为nlen-1的结点pp.next=null; //将结点p置为尾结点}
7、返回线性表中序号为i的元素
public E GetElem(int i) //返回线性表中序号为i的元素{int len=size();if (i<0 || i>len-1)throw new IllegalArgumentException("查找:位置i不在有效范围内");DLinkNode<E> p=geti(i); //找到序号为i的结点preturn (E)p.data;}
8、设置序号i的元素为e
public void SetElem(int i,E e) //设置序号i的元素为e{if (i<0 || i>size()-1)throw new IllegalArgumentException("设置:位置i不在有效范围内");DLinkNode<E> p=geti(i); //找到序号为i的结点pp.data=e;}
9、查找第一个为e的元素的序号
public int GetNo(E e) //查找第一个为e的元素的序号{int j=0;DLinkNode<E> p=dhead.next; while (p!=null && !p.data.equals(e)){j++; //查找元素ep=p.next;}if (p==null) //未找到时返回-1return -1;elsereturn j; //找到后返回其序号}
10、在线性表中序号i位置插入元素e
public void Insert(int i, E e) //在线性表中序号i位置插入元素e{if (i<0 || i>size()) //参数错误抛出异常throw new IllegalArgumentException("插入:位置i不在有效范围内");DLinkNode<E> s=new DLinkNode<E>(e); //建立新结点s DLinkNode<E> p=dhead=geti(i-1); //找到序号为i-1的结点p,其后插入s结点s.next=p.next; //修改s结点的next字段if (p.next!=null) //修改p结点的非空后继结点的prior字段p.next.prior=s;p.next=s; //修改p结点的next字段s.prior=p; //修改s结点的prior字段}
11、在线性表中删除序号i位置的元素
public void Delete(int i) //在线性表中删除序号i位置的元素{if (i<0 || i>size()-1) //参数错误抛出异常throw new IllegalArgumentException("删除:位置i不在有效范围内");DLinkNode<E> p=geti(i); //找到序号为i的结点p,删除该结点p.prior.next=p.next; //修改p结点的前驱结点的next字段if (p.next!=null) //修改p结点非空后继结点的prior字段p.next.prior=p.prior;}
12、将线性表转换为字符串
public String toString() //将线性表转换为字符串{String ans="";DLinkNode<E> p=dhead.next;while (p!=null){ans+=p.data+" ";p=p.next;}return ans;}
13、双链表完整代码
import java.util.*;
@SuppressWarnings("unchecked")
class DLinkNode<E> //双链表结点泛型类
{E data;DLinkNode<E> prior; //前驱结点指针DLinkNode<E> next; //后继结点指针public DLinkNode() //构造方法{ prior=null;next=null;}public DLinkNode(E d) //重载构造方法{data=d;prior=null;next=null;}
}public class DLinkListClass<E> //双链表泛型类
{DLinkNode<E> dhead; //存放头结点public DLinkListClass() //构造方法{dhead=new DLinkNode<E>(); //创建头结点dhead.prior=null;dhead.next=null;}private DLinkNode<E> geti(int i) //返回序号为i的结点{DLinkNode<E> p=dhead;int j=-1;while (j<i){j++;p=p.next;}return p;}//线性表的基本运算算法 public void CreateListF(E[] a) //头插法:由数组a整体建立双链表{DLinkNode<E> s;for (int i=0;i<a.length;i++) //循环建立数据结点s{s=new DLinkNode<E>(a[i]); //新建存放a[i]元素的结点s,将其插入到表头s.next=dhead.next; //修改s结点的next字段if (dhead.next!=null) //修改头结点的非空后继结点的prior字段dhead.next.prior=s;dhead.next=s; //修改头结点的next字段s.prior=dhead; //修改s结点的prior字段}}public void CreateListR(E[] a) //尾插法:由数组a整体建立双链表{DLinkNode<E> s,t;t=dhead; //t始终指向尾结点,开始时指向头结点for (int i=0;i<a.length;i++) //循环建立数据结点s{ s=new DLinkNode<E>(a[i]); //新建存放a[i]元素的结点st.next=s; //将s结点插入t结点之后s.prior=t; t=s;}t.next=null; //将尾结点的next字段置为null}public void Add(E e) //在线性表的末尾添加一个元素e{DLinkNode<E> s=new DLinkNode<E>(e); //新建结点sDLinkNode<E> p=dhead;while (p.next!=null) //查找尾结点pp=p.next;p.next=s; //在尾结点之后插入结点ss.prior=p;}public int size() //求线性表长度{DLinkNode<E> p=dhead;int cnt=0;while (p.next!=null) //找到尾结点为止{cnt++;p=p.next;}return cnt;}public void Setsize(int nlen) //设置线性表的长度{int len=size();if (nlen<0 || nlen>len)throw new IllegalArgumentException("设置长度:n不在有效范围内");if (nlen==len) return;DLinkNode<E> p=geti(nlen-1); //找到序号为nlen-1的结点pp.next=null; //将结点p置为尾结点}public E GetElem(int i) //返回线性表中序号为i的元素{int len=size();if (i<0 || i>len-1)throw new IllegalArgumentException("查找:位置i不在有效范围内");DLinkNode<E> p=geti(i); //找到序号为i的结点preturn (E)p.data;}public void SetElem(int i,E e) //设置序号i的元素为e{if (i<0 || i>size()-1)throw new IllegalArgumentException("设置:位置i不在有效范围内");DLinkNode<E> p=geti(i); //找到序号为i的结点pp.data=e;}public int GetNo(E e) //查找第一个为e的元素的序号{int j=0;DLinkNode<E> p=dhead.next; while (p!=null && !p.data.equals(e)){j++; //查找元素ep=p.next;}if (p==null) //未找到时返回-1return -1;elsereturn j; //找到后返回其序号}public void Insert(int i, E e) //在线性表中序号i位置插入元素e{if (i<0 || i>size()) //参数错误抛出异常throw new IllegalArgumentException("插入:位置i不在有效范围内");DLinkNode<E> s=new DLinkNode<E>(e); //建立新结点s DLinkNode<E> p=dhead=geti(i-1); //找到序号为i-1的结点p,其后插入s结点s.next=p.next; //修改s结点的next字段if (p.next!=null) //修改p结点的非空后继结点的prior字段p.next.prior=s;p.next=s; //修改p结点的next字段s.prior=p; //修改s结点的prior字段}public void Delete(int i) //在线性表中删除序号i位置的元素{if (i<0 || i>size()-1) //参数错误抛出异常throw new IllegalArgumentException("删除:位置i不在有效范围内");DLinkNode<E> p=geti(i); //找到序号为i的结点p,删除该结点p.prior.next=p.next; //修改p结点的前驱结点的next字段if (p.next!=null) //修改p结点非空后继结点的prior字段p.next.prior=p.prior;}public String toString() //将线性表转换为字符串{String ans="";DLinkNode<E> p=dhead.next;while (p!=null){ans+=p.data+" ";p=p.next;}return ans;}
}
好啦!内容有点多!!!到此链表的内容已经学习完毕,学会上面全部内容,分分钟手撕链表不是问题!!!
关注我,持续更新数据结构与算法的内容,感兴趣的可以关注我的专栏!
《数据结构》线性表——链式存储结构相关推荐
- 线性表-链式存储结构
3.6 线性表的链式存储结构 3.6.1 顺序存储结构不足的解决办法 前面我们讲的线性表的顺序存储结构.它是有缺点的,最大的缺点就是插入和删除时需要移动大量元素,这显然就需要耗费时间.能不能想办法解决 ...
- php数据结构链表代码,数据结构之线性表——链式存储结构之单链表(php代码实现)...
/** * * 1. 类LNode用作创建单链表时,生成新的节点. * 2. 类SingleLinkList用于创建单链表以及对单链表的一些操作方法(实例化此类就相当于创建了一个空链表) * 3. C ...
- 数据结构之线性表——链式存储结构之单链表(php代码实现)
<?php /**** 1. 类LNode用作创建单链表时,生成新的节点.* 2. 类SingleLinkList用于创建单链表以及对单链表的一些操作方法(实例化此类就相当于创建了一个空链表)* ...
- 数据结构——线性表之链式存储结构
单链表: 概念: 1.由于线性表的顺序存储在插入与删除时需要移动大量元素,适用于不经常改变元素的情况,那么当我们需要经常操作元素时该怎么办,这就有了接下来的线性表的链式存储结构 2.单链表在内存的存储 ...
- 数据结构之线性表-链式存储之单链表(一)
本人文笔较差,语文从来不及格,基础不好,写此类文章仅供自己学习,理解队列及其他知识,高手大神请略过.参考书籍 <数据结构与算法分析-Java语言描述> 1.1 单链表简介 线性表的最大的缺 ...
- 线性表之链式存储结构_单链表相关算法
在存储结构上,不需要连续的存储空间,需要上一个结点的指针域 指向下一个结点即可,找到一个结点就可以找到下一个结点. 学习教材是大话数据结构,加上自己的一些个人理解.这个算法 有点绕,需要对指针 相关内 ...
- 线性表之链式存储结构
线性表的顺序存储结构,插入和删除时需要移动大量元素,耗费时间,可解决这些问题. 转载于:https://www.cnblogs.com/cailingsunny/p/4562287.html
- 数据结构(二)----线性表(List)链式存储结构(1)
线性表List---链式存储结构 相关概念 链式存储结构/链式表 定义 链式存储特点 单链表 单链表读取 单链表插入 单链表删除 时间复杂度 单链表整表创建 单链表整表删除 顺序存储与链式存储差异 P ...
- 数据结构和算法:(3)3.2线性表的链式存储结构
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素也就是说你这个可以放在A地点,这个可以放在E地点,A地点和E地点中间可以隔开一个C地点和D地点,这样是允许的),这组存储单元可以存在 ...
- 利用链式存储结构实现线性表
本图文主要介绍了如何利用链式存储结构实现线性表.
最新文章
- luogu P2365 任务安排(FJOI2019 batch)
- ajax(jquery)前后台传数组(Springmvc后台)
- 清华大学计算机组成与体系结构,清华大学出版社-图书详情-《计算机组成与体系结构(第2版)》...
- Django框架 from django.core.files.uploadedfile import InMemoryUploadedFile
- app-debug.apk does not exist on disk
- 牛逼!终于有人开源了一份基于SSM框架实现了支付宝支付功能的完整源代码......
- Qt开发技术:Qt绘图系统(二)QPainter详解
- 软件备份(拷贝构造函数)
- 第三届“马栏山杯” 国际音视频算法大赛
- 趋势杀毒软件卸载方法(卸载密码破解)
- 博士申请 | 香港城市大学刘晨老师组招收机器学习方向全奖博士/博后/硕士/RA...
- 在人工智能领域创业,需要明确可知的5个基本条件
- Help Hanzo(LightOJ - 1197)(欧拉筛 + 思维)
- 帝国时代2决定版多人游戏服务器维护,帝国时代2决定版怎么在多人模式中玩战役 多人战役方法一览_游侠网...
- Mysql服务器安装步骤
- 利用JS制作抖音同款3D照片墙(three.js)
- 100天精通Oracle-实战系列(第16天)使用 RMAN 备份快速恢复误删数据表
- 一个计算数独的小程序
- 暴力英语学习法 + 严格的目标管理 = 成功快速靠谱的学好英语
- 成功解决需要Xmanager软件来处理X11转发需求