简介
线性表分为:顺序表,链表,栈和队列 结构上:顺序存储结构 & 链式存储结构
顺序表 & 顺序存储结构
实现:数组
特点:
- 存储线性表的数据元素的方式 = 一段地址连续的存储单元
- 具备:起始位置、数组长度(最大存储容量) & 线性表长度(当前长度)
操作:
顺序存储结构的操作包括:插入 & 删除
链式存储结构
实现:链表
特点:链式存储结构的数据元素的方式 = 一段地址不连续的存储单元
区分:单链表、双向链表、循环链表、静态链表
单链表
特点:链式存取的数据结构,单链表中的数据是以结点的形式存在,每一个结点是由数据元素和下一个结点的存储的位置组成。每个结点只有1个指针域
结点
单链表实现
public class UnidirectionalLinkedList<T> {
/**
* 设置结点结构
*/
// a. 结点结构
private class Node<T>{
private T data;
private Node<T> next ;
public Node(T data){
this.data = data;
}
}
// b. 头结点
private Node<T> first;
// c. 当前结点
private Node<T> currentNode;
// d. 链表长度
private int size;
/**
* 构造函数
* 作用:初始化结点
*/
public UnidirectionalLinkedList(){
currentNode = first = null;
size = 0;
}
/**
* 1. 添加结点
* 内容:在头 / 尾 添加结点 & 在特定位置插入结点
*/
// a. 在链表头部加入1个结点
// 即,把新加入的结点设置为第一结点
public void addFirstNode(T data){
// 1. 将需添加的内容封装成结点
Node<T> newNode = new Node<T>(data);
// 2. 将新添加结点的指针域指向旧第1个结点
newNode.next = first;
// 3. 将新添加结点设置为第1个结点
first = newNode;
// 4. 链表长度+1
size++;
}
// b. 在链表尾部加入1个结点
// 即,把新加入的结点设置为最后结点
public void addNode(T data){
// 1. 检查当前链表是否为空
if (isEmpty()){
addFirstNode(data);
return;
}
// 2. 把当前指针定位到最后一个结点
locateNode(size-1);
// 3. 将需添加的内容封装成结点
currentNode.next = new Node<T>(data);
// 4. 链表长度+1
size++;
}
// c. 在链表中插入结点
public T insertNode(int index, T data) {
// 1. 检查当前链表是否为空
if (isEmpty()){
addFirstNode(data);
return null;
}
// 2. 把当前指针定位到需插入的结点位置
locateNode(index);
// 3. 将需添加的内容封装成结点
Node<T> insertNode = new Node<T>(data);
// 4. 把需插入结点位置的下1个结点 赋给 插入的结点
insertNode.next = currentNode.next;
// 5. 把插入结点 赋给 需插入的结点的位置
currentNode.next = insertNode;
// 6. 链表长度+1
size++;
// 7. 返回插入结点的数据
return insertNode.data;
}
/**
* 2. 删除结点
* 内容:删除第1个结点 & 删除特定位置的结点
*/
// a. 删除第1个结点,并返回该结点数据
public T removeFirstNode() {
// 1. 检查当前链表第一个结点是否为空
if (first == null){
try {
throw new Exception("链表为空!");
} catch (Exception e) {
e.printStackTrace();
}
}
// 2. 获取被删除结点的数据
T temp = first.data;
// 3. 将第2个结点设置为第1个结点
first = first.next;
// 4. 链表长度减1
size--;
// 5. 返回被删除结点的数据
return temp;
}
// b. 删除特定位置的结点,并将里面的数据返回
public T removeNode(int index) {
// 1. 检查当前链表是否为空
if (isEmpty()){
try {
throw new Exception("链表为空!");
} catch (Exception e) {
e.printStackTrace();
}
}
// 2. 把当前指针(currentNode)定位到 需删除结点(index)的前1个结点
locateNode(index-1);
// 3. 获取被删除结点的数据
T temp = currentNode.next.data;
// 4. 将需删除结点(index)的前1个结点 的下1个结点 设置为 需删除结点(index)的下1个结点
currentNode.next = currentNode.next.next;
// 5. 链表长度减1
size--;
// 6. 返回被删除结点的数据
return temp;
}
/**
* 3. 获取特定位置的结点
* 内容:将当前指针(currentNode)定位到所需结点位置、根据索引位置获取结点数据
*/
// a. 将当前指针(currentNode)定位到所需结点位置
private void locateNode(int index){
// 1. 判断指针是否越界
if (index <0 && index >size){
try {
throw new IndexOutOfBoundsException("参数越界!");
} catch (Exception e) {
e.printStackTrace();
}
}
int i = 0;
// 2. 通过遍历链表,寻找索引index所指结点
for(currentNode = first; currentNode.next != null && i < index; i++){
currentNode = currentNode.next;
}
}
// b. 根据索引位置获取结点数据
public T getNode(int index) {
// 1. 判断链表是否为空
if (isEmpty()){
try {
throw new Exception("链表为空!");
} catch (Exception e) {
e.printStackTrace();
}
}
// 2. 把当前指针(currentNode)定位到 所需索引位置(index)
locateNode(index);
// 3. 返回当前指针的数据,即所需索引位置的数据
return currentNode.data;
}
/**
* 检查当前链表是否为空
*/
public boolean isEmpty(){
if (size == 0){
return true;
}else {
return false;
}
}
public static void main(String[] args){
// 1. 创建链表 & 加入结点数据
UnidirectionalLinkedList<Integer> list = new UnidirectionalLinkedList<Integer>();
list.addNode(1);
list.addNode(2);
list.addNode(3);
list.addNode(4);
list.addNode(5);
// 2. 输出当前链表数据
System.out.println("链表数据如下:");
for (int i = 0; i < list.size;i++){
try {
System.out.print(list.getNode(i)+" ");
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("-----------------------");
// 3. 获得某个位置结点的数据
System.out.println("位置3的数据是:" + list.getNode(3));
System.out.println("-----------------------");
// 4. 插入结点:在位置4插入,数据 = 66
System.out.println("在位置4插入的data:"+list.insertNode(3,66));
System.out.println("插入后:");
for (int i = 0; i < list.size;i++){
try {
System.out.print(list.getNode(i)+" ");
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("-----------------------");
// 5. 删除结点
System.out.println("删除index为3的data:"+list.removeNode(3));
System.out.println("删除后:");
for (int i = 0; i < list.size;i++){
try {
System.out.print(list.getNode(i)+" ");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
循环列表,
将单链表的终端结点的指针指向头结点、使得单链表头尾相接、形成1个环
双向链表
特点:每个结点有2个指针域:1指向后驱结点元素、2指向前驱结点元素
package com.struct.linklist;
/**
* @描述 双向链表
* @项目名称 Java_DataStruct
* @包名 com.struct.linklist
* @类名 LinkList
* @author chenlin
* @date 2010年6月26日 上午8:00:28
* @version 1.0
*/
public class DoubleLinkList {
//头
private Node first;
//尾
private Node last;
public DoubleLinkList(){
first = null;
last = null;
}
/**
* 插入数据
* @param value
*/
public void insertFirst(long value){
Node newNode = new Node(value);
if (first == null) {
last = newNode;
}else {
first.previous = newNode;
//把first节点往下移动
newNode.next = first;
}
//把插入的节点作为新的节点
first = newNode;
}
/**
* 插入数据
* @param value
*/
public void insertLast(long value){
Node newNode = new Node(value);
if (first == null) {
first = newNode;
}else {
last.next = newNode;
//first.previous = newNode;
newNode.previous = last;
}
//把最后个节点设置为最新的节点
last = newNode;
}
public boolean isEmpty(){
return first == null;
}
/**
* 删除头节点时要去除两个指针,一个指向下个的next ,一个是next的previous指向前面的
*
* @param value
* @return
*/
public Node deleteFirst(){
if (first == null) {
throw new RuntimeException("链表数据不存在");
}
Node temp = first;
if (first.next == null) {
last = null;
}else {
first.next.previous = null;
}
first = temp.next;
return temp;
}
/**
* 删除头节点时要去除两个指针,一个指向下个的next ,一个是next的previous指向前面的
*
* @param value
* @return
*/
public Node deleteLast(){
if (first == null) {
throw new RuntimeException("链表数据不存在");
}
Node temp = last;
if (first.next == null) {
last = null;
//把第一个删除
first = null;
}else {
last.previous.next = null;
}
last = temp.previous;
return temp;
}
/**
* 删除
* @param key
* @return
*/
public Node deleteByKey(long key){
Node current = first;
while(current.data != key){
if (current.next == null) {
System.out.println("没找到节点");
return null;
}
current = current.next;
}
if (current == first) {
//return deleteFirst();
//指向下个就表示删除第一个
first = first.next;
}else {
current.previous.next = current.next;
}
return current;
}
/**
* 显示所有的数据
*/
public void display(){
if (first == null) {
//throw new RuntimeException("链表数据不存在");
return;
}
Node current = first;
while(current != null){
current.display();
current = current.next;
}
System.out.println("---------------");
}
/**
* 查找节点1
* @param value
* @return
*/
public Node findByValue(long value){
Node current = first;
while(current != null){
if (current.data != value) {
current = current.next;
}else {
break;
}
}
if (current == null) {
System.out.println("没找到");
return null;
}
return current;
}
/**
* 查找节点2
*
* @param key
* @return
*/
public Node findByKey(long key) {
Node current = first;
while (current.data != key) {
if (current.next == null) {
System.out.println("没找到");
return null;
}
current = current.next;
}
return current;
}
/**
* 根据索引查找对应的值
* @param position
* @return
*/
public Node findByPosition(int position){
Node current = first;
//为什么是position - 1,因为要使用遍历,让current指向下一个, 所以position - 1的下个node就是要找的值
for (int i = 0; i < position - 1 ; i++) {
current = current.next;
}
return current;
}
public static void main(String[] args) {
DoubleLinkList linkList = new DoubleLinkList();
linkList.insertFirst(21);
linkList.insertFirst(22);
linkList.insertFirst(23);
linkList.insertLast(24);
linkList.insertLast(25);
linkList.insertLast(26);
linkList.insertLast(27);
linkList.display();
System.out.println("---查找-------------------------------------");
linkList.findByKey(25).display();
System.out.println("--删除first-------------------------------------");
//linkList.deleteFirst().display();
///linkList.deleteFirst().display();
//linkList.deleteFirst().display();
//linkList.deleteFirst().display();
System.out.println("-删除指定值---------------------------------------");
linkList.deleteByKey(27).display();
linkList.deleteByKey(21).display();
System.out.println("----------------------------------------");
linkList.display();
}
}
静态链表
用数组描述的链表,即称为静态链表。 特点:这种存储结构,仍需要预先分配一个较大的空间,但在作为线性表的插入和删除操作时不需移动元素,仅需修改指针,故仍具有链式存储结构的主要优点。
//实现
/**
* @DESCRIPTION TODO
* @DATE 2019年3月23日 下午9:08:11
* @AUTHOR tmooming
*/
public class SNode<T> {
public T data;
private int cursor;
public SNode() {
}
public SNode(T data, int cursor) {
this.data = data;
this.cursor = cursor;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public int getCursor() {
return cursor;
}
public void setCursor(int cursor) {
this.cursor = cursor;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(getData());
sb.append(" ");
sb.append(getCursor() + " ");
return sb.toString();
}
}
/**
* @DESCRIPTION TODO
* @DATE 2019年3月23日 下午9:08:23
* @AUTHOR tmooming
*/
public class SList<T> {
SNode<T>[] node;
private static final int MAX_SIZE = 15;
private int length;
public SList() {
node = new SNode[MAX_SIZE];
for (int i = 0; i < MAX_SIZE - 1; i++) {
node[i] = new SNode<T>(null, i + 1);
}
node[MAX_SIZE - 1] = new SNode<>(null, 0);
this.length = 0;
}
// 实际数组长度
public int Length() {
return length;
}
// 判断使用数组是否为空
public boolean isEmpty() {
return length == 0;
}
// 判断备用链表是否为空
public boolean isFull() {
return length == MAX_SIZE;
}
// 插入一个节点
public boolean addTo(T data, int index) {
if (isFull() || index > MAX_SIZE || index < -1 || data == null)
return false;
if (index == 0) {
insert(data);
return true;
}
if (index > Length()) {
index = Length();
}
// 获取第一个使用节点的下标
int firstUse = node[MAX_SIZE - 1].getCursor();
// 获取备用数组第一个节点的下标
int firstNull = node[0].getCursor();
for (int i = 1; i < index; i++) {
firstUse = node[firstUse].getCursor();
}
// 获取目标节点的后续节点
int nextUse = node[firstUse].getCursor();
int nextNull = node[firstNull].getCursor();
node[0].setCursor(nextNull);
node[firstUse].setCursor(firstNull);
node[firstNull].setCursor(nextUse);
node[firstNull].setData(data);
length++;
return true;
}
public void insert(T data) {
int t = node[MAX_SIZE - 1].getCursor();
int firstNull = node[0].getCursor();
node[MAX_SIZE - 1].setCursor(firstNull);
node[0].setCursor(node[firstNull].getCursor());
node[firstNull].setCursor(t);
node[firstNull].setData(data);
length++;
}
public void print() {
int first = node[MAX_SIZE - 1].getCursor();
System.out.println("链表:");
for (int i = first; i != 0;) {
System.out.print(node[i].getData() + " ");
i = node[i].getCursor();
}
}
// 删除指定节点
public boolean delete(T data) {
if (isEmpty()) {
return false;
}
int temp = MAX_SIZE - 1;
while (temp != 0) {
if (node[node[temp].getCursor()].getData() == data) {
int p = node[temp].getCursor();
node[temp].setCursor(node[p].getCursor());
node[p].setCursor(node[0].getCursor());
node[0].setCursor(p);
node[p].setData(null);
length--;
return true;
}
temp = node[temp].getCursor();
}
return false;
}
// 删除所有节点
public boolean deleteAll() {
if (isEmpty()) {
return true;
}
for (int i = 0; i < MAX_SIZE - 1; i++) {
node[i].setCursor(i + 1);
node[i].setData(null);
}
node[MAX_SIZE - 1].setCursor(0);
node[MAX_SIZE - 1].setData(null);
length = 0;
return true;
}
public void printAll() {
System.out.println("链表:");
for (int i = 0; i < MAX_SIZE; i++) {
System.out.print("[" + i + " " + node[i].getData() + " " + node[i].getCursor() + "]");
if (i % 5 == 0 && i != 0) {
System.out.println();
}
}
}
public static void main(String[] args) {
SList<String> list = new SList<String>();
list.insert("赵");
list.insert("钱");
list.insert("李");
// list.printAll();
// list.addTo("孙", 5);
list.deleteAll();
System.out.println(list.Length());
list.printAll();
}
}