【数据结构】线性表
线性表
1 线性表的逻辑结构
1.1 线性表的定义
线性表(Linear List)是一种线性结构。在一个线性表中数据元素的类型是相同的,或者说线性表是由同一类型的数据元素构成的线性结构。定义如下:
线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列,通常记为:
(a1,a2,...,ai-1,ai,ai+1,an)
其中n为表长,当n=0时称该线性表为空表。
1.2 线性表的基本操作
数据结构中元素的操作(或称运算)是定义在逻辑结构层次上的,而操作的具体实现是建立在存储结构上的,因此下面定义的线性表的金恩操作作为逻辑结构的一部分,每一个操作的具体实现只有在确定了线性表的存储结构之后才能完成。
即根据逻辑操作定义接口,根据存储结构进行实现。
1.线性表初始化:Init_List(L)
2.求线性表的长度:Length_List(L)
3.取表元:Get_List(L, i)
4.按值查找:Locate_List(L, x)
5.插入操作:Insert_List(L, i, x)
6.删除操作:Delete_List(L, i)
2 顺序表
线性表的顺序存储是指在内存中用地址连续的一块存储空间顺序存放线性表中的各数据元素,用这种存储形式存储的线性表成为顺序表。因为内存中的地址空间是线性的,所以用物理位置关系上的相邻性实现数据元素之间的逻辑相邻关系既简单又自然。
设a1的存储地址为Loc(a1),每个数据源元素占d个存储单元,则第i个数据元素的地址为:
Loc(ai)= Loc(a1) + (i-1)*d 1=<i<=n
这就是说,只要知道顺序表首地址和没个数据元素所占用单元的个数就可求出第i个数据元素的地址来,这也是顺序表具有按数据元素的序号随机存取的特点。
2.1 顺序表基本操作的实现
1.线性表初始化
class InitList{ private int length; //顺序表长度,表示顺序表中的元素个数 private int [] list; //数组,顺序表主体 public InitList(int max){ //构造函数,用来初始化顺序表时定义顺序表的最大长度 this.list = new int[max]; this.length = 0; } }
2.求线性表的长度:Length_List(L)
public int listLength() { return this.length; //同上返回length值即可 }
3.取表元:Get_List(L, i)
public int [] getElem(int site) { int [] ret = new int[1]; //用来存储获取的值 if(site < 1 || site > this.length) { //检测输入的位置是否合法 return null; } ret[0] = this.list[site - 1]; //获取指定位置的值 return ret; }
4.按值查找:Locate_List(L, x)
public int [] getElem(int site) { int [] ret = new int[1]; //用来存储获取的值 if(site < 1 || site > this.length) { //检测输入的位置是否合法 return null; } ret[0] = this.list[site - 1]; //获取指定位置的值 return ret; }
5.插入操作:Insert_List(L, i, x)
public int listInsert(int site,int value) { if(site < 1 || site > this.length + 1) { //判断输入的位置是否合法 return -1; }else if(this.length == this.list.length) { //判断顺序表是否已满 return -2; } for(int i = this.length - 1; i >= site - 1; i--) { //从顺序表的最后一个元素开始,逐个向后移动一位,直到要插入元素的位置,为要插入的元素腾出空间 this.list[i+1] = this.list[i]; } this.list[site - 1] = value; //插入元素 this.length++; //顺序表长度加一 return 0; }
6.删除操作:Delete_List(L, i)
public boolean listDelete(int site) { if(site < 1 || site > this.length) { //判断输入的位置是否合法 return false; }else if(site == this.length) { //如果要删除的是最后一个元素,直接将顺序表长度减一即可 this.length--; return true; }else { for (int i = site - 1; i < this.length; i++) { //从要删除元素的位置开始,将后面的元素逐个向前移动一位,填补删除元素后的空缺 this.list[i] = this.list[i + 1]; } this.length--; //顺序表长度减一 return true; } }
3 单链表
由于顺序表的存储特点是用物理上的相邻关系实现逻辑上的相邻关系,他要求用连续的存储单元顺序存储线性表中的各元素,因此,在对顺序表插入、删除时,需要通过移动数据元素来实现,影响了运行效率。
链式存储结构中,它不需要用地址连续的存储单元来实现,因此他不要求逻辑上相邻的数据元素在物理上也相邻。在链式存储结构中,数据元素之间的逻辑关系是通过“链”来连接的,因此对线性表的插入、删除不需要移动数据元素。
1.线性表初始化:Init_List(L)
class InitList{ private int [] data = new int[1]; //用来存储元素值,之所以用数组而不用整型,是为了用null来表示头结点 private InitList nextList; //下一结点地址 public InitList() { //创建头结点的构造函数 this.data = null; this.nextList = null; } public InitList(int data) { //创建普通结点的构造函数 this.data[0] = data; this.nextList = null; } }
2.求线性表的长度:Length_List(L)
public int listLength() { InitList theList = this.nextList; //获取头结点的下一结点地址 int i = 0; //计数器初始化 for (i = 0; theList != null; i++) { //循环判断结点地址是否为空,如果不为空,则表明存在结点,计数器i加一;如果为空,则表明已到达单链表尾部,退出循环 theList = theList.nextList; //取下一结点进行判断 } return i; //返回计数器的值 }
3.取表元:Get_List(L, i)
public int [] getElem(int site) { if(site < 1) { //判断输入的位置是否合法 return null; } InitList theList = this; //得到头结点的地址 for (int i = 0; i < site; i++) { //循环读取结点,直到指定的位置 theList = theList.nextList; //获取下一结点的地址 if(theList == null) { //如果下一结点地址为空,则表明已经到达单链表末尾,指定的位置超出了单链表的长度 return null; //未取到元素,返回null } } return theList.data; //返回指定位置元素值 }
4.按值查找:Locate_List(L, x)
public int locateElem(int value) { InitList theList = this.nextList; for(int i = 1; theList != null; i++) { //如果取得的结点不为空,执行循环 if(theList.data[0] == value) { //比较结点值与给定的值是否相等 return i; //相等返回结点位置 } theList = theList.nextList; //取下一结点地址 } return 0; //未找到则返回零 }
5.插入操作:Insert_List(L, i, x)
public boolean listInsert(int site,int value) { if(site < 1) { //判断指定位置是否合法 return false; } 7 InitList list = new InitList(value); InitList theNextList = this; InitList theList = null; for(int i = 0; i < site; i++) { //循环读取到指定位置 theList = theNextList; if(theList == null) { //如果为空,表示已到单链表末尾,返回false return false; } theNextList = theNextList.nextList; } list.nextList = theNextList; //将新结点插入指定位置中 theList.nextList = list; return true; }
6.删除操作:Delete_List(L, i)
public boolean listDelete(int site) { InitList theList = this; InitList theNextList = this.nextList; if(site < 1 || theNextList == null) { //判断指定位置是否合法和单链表是否为空 return false; }else if(site == 1) { //如果要删除的是第一个结点,则直接删除 theList.nextList = theNextList.nextList; return true; } for(int i = 1; i < site; i++) { //循环读取到指定位置 theNextList = theNextList.nextList; if(theNextList == null) { return false; } theList = theList.nextList; } theList.nextList = theNextList.nextList; //删除指定位置的结点 return true; }
4 双向链表
1.线性表初始化:Init_List(L)
public class Node { public Object e; public Node next; public Node pre; public Node(){ } public Node(Object e){ this.e = e; next = null; pre = null; } } public class DoubleLink{ private Node head; private Node tail; private int theSize; /* * 构造函数 我们构造了一个带有头、尾节点的双向链表 头节点的Next指向尾节点 为节点的pre指向头节点 链表长度起始为0。 */ public DoubleLink() { theSize = 0; Header = new Node<T>(null, null, null); Tail = new Node<T>(null, Header, null); Header.next = Tail; } }
2.求线性表的长度:Length_List(L)
public int size() { return this.theSize; }
3.取表元:Get_List(L, i)
public T getInt(int index) { if (index > this.theSize - 1 || index < 0) throw new IndexOutOfBoundsException(); Node<T> current = Header.next; for (int i = 0; i < index; i++) { current = current.next; } return current.data; }
4.按值查找:Locate_List(L, x)
同单链表
5.插入操作:Insert_List(L, i, x)
public void add(T item) { Node<T> aNode = new Node<T>(item, null, null); Tail.pre.next = aNode; aNode.pre = Tail.pre; aNode.next = Tail; Tail.pre = aNode; theSize++; }
posted on 2020-05-17 17:42 kingszelda 阅读(725) 评论(0) 编辑 收藏 举报