线性表主要由顺序表示或链式表示。在实际应用中,常以栈、队列、字符串等特殊形式使用。
逻辑结构
线性表是最简单、最基本、也是最常用的一种线性结构,数据结构中的元素存在一对一的相互关系。 线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列,通常记为: (a1,a2,… ai-1,ai,ai+1,…an) ,其中n为表长, n=0 时称为空表。 它有两种存储方法:顺序存储和链式存储,它的主要基本操作是插入、删除和检索等。
存储结构
顺序存储结构
用一组地址连续的存储单元依次存放线性表中的数据元素。
典型代表
Array
链式存储结构
- 每个元素用一个结点表示,结点有数据域和指针域,元素之间的逻辑关系用指针维护 。
- 每个数据元素在物理存储空间可以不相邻
- 数据元素之间的线性关系由指针链接保证
典型代表
LinkedList
Doubly Linked List
顺序存储结构和链式存储结构的区别
顺序存储结构 | 链式存储结构 | |
---|---|---|
Access | O(1):L.elem[i-1] | O(n) :执行i次 p=p->next |
Insert | 平均 O(n) :要移动数据元素n-i+1次,平均移动次数=n/2 | O(1):申请空间和调整ai-1的指针 |
Delete | 平均 O(n):移动数据元素n-i次 | O(1) :调整ai-1的指针 |
适用场景 | 适用于大小固定,变化较少的线性表(增加或者删除的是最后1个数据元素) | 链式存储结构适用于 大小不固定,变化较大的线性表 (增加或者删除的是第1个数据元素) |
实战题目
逆置线性表
https://leetcode.com/problems/reverse-linked-list/
Example:
Input: 1->2->3->4->5->NULL
Output: 5->4->3->2->1->NULL
逆置顺序表
方法一
/**
* 逆置顺序表:方法一
*
* @param seqL 1,2,3,4,5
* @param <T>
* @return seqL 5,4,3,2,1
*/
public static <T> T[] reverseSeqL1(T[] seqL) {
if (null != seqL && seqL.length > 1) {
T temp;
for (int i = 1; i <= seqL.length / 2; i++) {
temp = seqL[i - 1];
seqL[i - 1] = seqL[seqL.length - i];
seqL[seqL.length - i] = temp;
}
}
return seqL;
}
方法二
/**
* 逆置顺序表:方法二
*
* @param seqL 1,2,3,4,5
* @param <T>
* @return seqL 5,4,3,2,1
*/
public static <T> T[] reverseSeqL2(T[] seqL) {
if (null != seqL && seqL.length > 1) {
T temp;
for (int i = 1, j = seqL.length; i < j; i++, j--) {
temp = seqL[i - 1];
seqL[i - 1] = seqL[j - 1];
seqL[j - 1] = temp;
}
}
return seqL;
}
逆置线性链表
ai的前驱变成了后继,后继变成了前驱,该问题的核心是要修改数据元素的邻里关系。
- p指向要修改指针的结点,初始时是a1;
- q指向p的后继,否则,修改p的指针,链就断了;
- t指向p的前驱,在新表中t是p的后继;
- q=p->next,p->next=t,t=p,p=q;
- 重复执行,直到p为空指针。
public class LinkedListTest {
private static class Node<E> {
E item;
Node<E> next;
Node(E element) {
this.item = element;
}
}
/**
* 逆置线性链表
* p:当前节点,t:前驱节点,q:后继节点
*
* @param head
* @return node
*/
public static Node reverseLinkedL(Node head) {
Node t = null, p = head, q;
while (p != null) {
q = p.next;
p.next = t;
t = p;
p = q;
}
return t;
}
}