Java | Data Structure - Construction of Linear Table [Sequence Table + Linked List] and its basic operations (code with comments, super detailed)

1. What is a linear table?

A linear table is a finite sequence composed of n (n≥0) data elements, usually expressed as (a0,a1,...,ai,...,an-1).

Method to realize:

One is based on the implementation of sequential storage - sequence table ;

The other is based on the implementation of linked storage - linked list .

2. Sequence table

1. Definition of sequence table

A sequential table is a linear table stored sequentially. Sequential storage is a storage structure in which each data element in the linear table is sequentially stored in a group of storage units with continuous addresses.

2. Features of the sequence table

  • The storage density is high, but it needs to pre-allocate "enough application" storage space, which may cause waste of storage space; where, storage density = storage space occupied by the value of the data element itself/space actually occupied by the data element;
  • facilitate random access;
  • It is inconvenient to insert and delete operations, because inserting and deleting operations on the sequence table will cause the movement of data elements.
  • Logically adjacent data elements in the linear table are also adjacent in physical storage location;

3. The construction of sequence table and its basic operation

//顺序表
public class SqList {
	
	private int[] listElem;  //顺序表存储空间
	private int curLen;  //顺序表当前长度
	
	public static void main(String[] args) throws Exception {
		//测试
		SqList sq = new SqList(5);  //构造容量空间为5的顺序表
		sq.display();  //遍历
		System.out.println();
		sq.insert(3, 2);  //插入
		sq.display();  //遍历
		System.out.println();
		System.out.println(sq.indexOf(2));  //查找-按值查下标
		System.out.println(sq.get(3));  //查找-按下标查值
		sq.remove(3);  //删除
		sq.display();  //遍历
		
	}
	//构造方法-构造一个存储空间容量为maxSize的顺序表
	public SqList(int maxSize) {
		curLen = 0;  //置顺序表的当前长度为0
		this.listElem = new int[maxSize];  //为顺序表分配maxSize个存储单元
	}
	
	//1. 将一个已经存在的顺序表置空
	public void clear() {
		curLen = 0;
	}
	
	//2. 判断顺序表是否为空
	public boolean isEmpty() {
		return curLen == 0;
	}
	
	//3. 返回顺序表中的数据元素个数
	public int length() {
		return curLen;
	}

	//4. (查找)返回顺序表中第i个数据元素
	public int get(int i) throws Exception{
		if(i<0 || i>listElem.length-1)
			throw new Exception("第" + i + "个元素不存在");  //不存在则抛出异常
		return listElem[i];
	}
	
	//5. 打印顺序表中的数据元素
	public void display() {
		for(int i=0;i<listElem.length;i++)
			System.out.print(listElem[i]);
	}
	
	//6. (插入)在顺序表的第i个数据元素之前插入一个值为x的数据元素
	public void insert(int i,int x) throws Exception{
		if(curLen == listElem.length)  //判断顺序表是否已满
			throw new Exception("顺序表已满");
		if(i<0 || i>listElem.length)  //判断i是否合法
			throw new Exception("插入位置不合理");
		for(int j=listElem.length-1;j>i;j--)
			listElem[j] = listElem[j-1];  //插入位置及其之后的所有数据元素后移
		listElem[i] = x;  //插入i
		curLen++;  //表长加1	
	}
	
	//7. (删除)删除顺序表中第i个元素
	public void remove(int i) throws Exception{
		if(i<0 || i>listElem.length)  //判断i是否合法
			throw new Exception("删除位置不合理");
		for(int j=i;j<listElem.length-1;j++)
			listElem[j] = listElem[j+1];  //删除位置及其之前的所有数据元素前移
		curLen--;  //表长减1
	}
	
	//8. (查找)返回顺序表中首次出现指定数据元素的位序号,若线性表中不包含此数据元素,则返回-1
	public int indexOf(int x) {
		int index = -1;
		for(int i=0;i<listElem.length;i++) {
			if(x == listElem[i])
				index = i;
		}
		return index;
	}
}

Test Results:

3. Linked list

1. Definition of linked list

Linked list , that is, a linear list of linked storage. Each node in the linked list contains a data field for storing data element values ​​and a pointer field for storing logically adjacent nodes .

Singly linked list : a node contains only one pointer field;

Circular linked list (circular linked list) : The structure is similar to that of a single linked list. The end of the single linked list is connected, that is, the successor pointer of the last node of the single linked list points to the first node, never forming a circular linked list;

Doubly linked list: A node has two pointer fields, one pointing to the predecessor node and one pointing to the successor node.

2. The characteristics of linked list

  • Dynamic storage allocation is adopted, which will not cause memory waste and overflow;
  • It is very convenient to perform insertion and deletion operations, just modify the pointer, and do not need to move a large number of elements.

3. The construction of singly linked list and its basic operation

//使用泛型构造结点类
public class Node<T> {
	public T data;  //存放结点值
	public Node<T> next;  //后继结点的引用
	//无参时的构造函数
	public Node(){
		this(null,null);
	}
	//带一个参数时的构造函数
	public Node(T data){
		this(data,null);
	}
	//带两个参数时的构造函数
	public Node(T data,Node<T> next)
	{
		this.data=data;
		this.next=next;
	}
}
import java.util.Scanner;
import Node;
//链表
public class LinkList<T>{
	
	public Node<T> head;  //单链表的头指针
	
	public static void main(String[] args) throws Exception{
		//测试
		LinkList<Integer> link = new LinkList<Integer>(5,true); //尾插法
		link.display();  //打印
		System.out.println(link.isEmpty());  //判空
		link.insert(link.length(),7);  //插入
		link.display();  //打印
		System.out.println(link.length());  //长度
		System.out.println(link.get(2));  //查找-按下标查找值
		System.out.println(link.indexOf(7));  //查找-按值查找下标
		link.remove(0);  //删除
		link.display();  //打印
	}
	//构造方法-构造一个带头结点的单链表
	public LinkList() {
		head = new Node<T>();  //初始化头结点	
	}
	//构造方法-构造一个长度为n的单链表
	public LinkList(int n,boolean Order) throws Exception{  
		this();  //调用无参构造方法初始化头结点
		
		if(Order)  //用尾插法顺序建立单链表
			create1(n);
		else
			       //用头插法逆序建立单链表
			create2(n);
	}
	
	//1. 用尾插法顺序建立单链表,其中n为单链表的结点个数
	public void create1(int n) throws Exception{
		Scanner sc = new Scanner(System.in);  //构造用于输入的对象
		for(int j=0;j<n;j++)   //输入n个结点的数据域值
			insert(length(), (T) sc.next());  //生成新结点,插入到表尾
	}
	
	//2. 用头插法逆序建立单链表,其中n为单链表的结点个数
	public void create2(int n) throws Exception{
		Scanner sc = new Scanner(System.in);  //构造用于输入的对象
		for(int j=0;j<n;j++)   //逆序输入n个结点的数据域值
			insert(0,(T) sc.next());  //生成新结点,插入到表头
	}
	
	//3. 将一个已经存在的带头结点单链表置成空表
	public void clear() {
		head.data = null;
		head.next = null;
	}
	
	//4. 判断带头结点的单链表是否为空
	public boolean isEmpty() {
		return head.next == null;
	}
	
	//5. 求带头结点的单链表的长度
	public int length() {
		Node<T> p = head.next;  //指针p指向头结点的下一个结点
		int length = 0;
		while(p != null) {
			p = p.next;  //指针向后移动
			++length;  //长度增加
		}
		return length;  //返回长度
	}
	
	//6. (查找)读取带头结点的单链表中的 第i个结点
	public T get(int i) throws Exception{
		Node<T> p = head.next;  //指针p指向头结点的下一个结点
		int j = 0;  //j为计数器
		while(p!=null && j<i) {  //从首结点开始向后查找,直到p指向第i个结点或p为空
			p = p.next;  //指向后继结点
			++j;  //计数器的值增1
		}
		if(j>i || p==null) {  //i小于0或者大于表长减1时,即i不合法
			throw new Exception("第" + i + "个元素不存在");  //抛出异常
		}
		return p.data;  //返回结点p的数据域值
	}
	
	//7. (查找)在带头结点的单链表中查找值为x的结点
	public int indexOf(T x) {
		Node<T> p = head.next;  //指针p指向头结点的下一个结点
		int j = 0;  //j为计数器
		//下面从单链表中的首结点开始查找,直到p.data为x或到达单链表的表尾
		while(p!=null && !p.data.equals(x)) {
			p = p.next;  //指向下一个结点
			++j;  //计数器的值增1
		}
		if(p!= null)
			return j;  //返回值为x的结点在单链表的位置
		else
			return -1;  //值为x的结点不在单链表中,则返回-1
	}
	
	//8. (插入)在带头结点的单链表中的第i个结点之前插入一个值为x的新结点
	public void insert(int i,T k) throws Exception {
		Node<T> p = head;  //初始化头结点
		int j = -1;  //j为计数器
		while(p!=null && j<i-1) {  //寻找第i个结点的前驱
			p = p.next;  
			++j;  //计数器的值增1
		}
		if(j>i-1 || p==null)  //i不合法
			throw new Exception("插入位置不合法");  //抛出异常
		Node<T> s = new Node<T>(k);  //生成新结点
		s.next = p.next;  //修改链,使新结点插入单链表中
		p.next = s;
	}
	
	//9. (删除)删除带头结点的单链表中的第i个结点
	public void remove(int i) throws Exception{
		Node<T> p = head;  //初始化头结点
		int j = -1;  //j为计数器
		while(p.next!=null && j<i-1) {  //寻找第i个结点的前驱
			p = p.next;  //指针后移
			++j;
		}
		if(j>i-1 || p.next==null) 
			throw new Exception("删除位置不合法");
		p.next = p.next.next;  //修改链指针,使待删除结点从单链表中脱离出来
	}
	
	//10. 输出单链表中的所有结点
	public void display() {
		Node<T> p = head.next;  //指针p指向头结点的下一个结点
		while(p != null) {
			System.out.print(p.data + " ");  //输出结点的值
			p = p.next;  //指针后移
		}
		System.out.println();  //换行
	}
	
}

Test Results:

Fourth, the comparison between sequence list and linked list

  • The linked list is more flexible, and the efficiency of insertion and deletion operations is high, but the space utilization rate of the linked list is low, which is suitable for linear tables with dynamic sight;
  • The implementation of the sequence table is relatively simple, because there are array types in any high-level programming language, and the space utilization rate is also high, and random access can be performed efficiently, but the sequence table is not easy to expand, and the efficiency of insertion and deletion operations is low, which is suitable for Realize a relatively "stable" static linear table.

Guess you like

Origin blog.csdn.net/weixin_49851451/article/details/125879954