一、概念
对于常用的数据结构,可分为线性结构和非线性结构,线性结构主要是线性表,非线性结构主要是数和图。当n>0时,表可表示为:(a0,a1,a2,a3,…an)
1、 线性表的特征:
1、存在唯一的被称作”第一个”的数据元素
2、存在唯一的一个称作”最后一个的”数据元素”
3、除第一个之外,集合中的每个数据元素均只有一个前驱
4、除最后一个之外,集合中每个元素均只有一个后继
2、线性表的基本操作
1、初始化:
2、返回线性表长度
3、获取指定索引处元素
4、按值查找元素位置
5、直接插入数据元素
6、向指定位置插入元素
7、直接删除元素
8、删除指定位置元素
二、顺序存储结构
线性表的顺序结构是指用一组地址连续的存储单元依次存放线性表的元素。下面采用数组实现顺序结构线性表。
import java.util.Arrays;
public class Sequence<T> {
private Object[] elementData; <span style="color: rgb(0, 153, 0); font-family: Arial;">//定义一个数组</span>
private int DEFAULT_SIZE = 1; <span style="color:#009900;">//数组默认大小</span>
private int capacity; <span style="color:#009900;">//数组容量</span>
private int size = 0; <span style="color:#009900;">//当前数组大小</span>
//初始化
public Sequence(){
capacity = this.DEFAULT_SIZE;
elementData = new Object[capacity];
}
public Sequence(T element){
this();
elementData[0] = element;
size++;
}
<span style="color:#009900;">//返回线性表长度</span>
public int length(){
return this.size;
}
<span style="color:#009900;">//返回指定索引处元素。</span>
public T getElementByIndex(int index){
if(index < 0 || index > (size-1)){
System.out.println("索引范围越界!!!");
System.exit(0);
}
return (T)elementData[index];
}
<span style="color:#009900;">//按值查找数据元素的位置</span>
public int getIndexByValue(T value){
for(int i = 0; i < elementData.length;i++ ){
if(value.equals(elementData[i])){
return i;
}
}
return -1;<span style="color:#009900;">//未找到则返回-1</span>
}
<span style="color:#009900;">//向指定位置插入元素</span>
public void insert(T element,int index){
ensureCapacity(); <span style="color:#009900;">//确保线性表容量够</span>
if(index >= 0 && index < size){
int i = 0;
<span style="color:#009900;">//将插入位置之后元素挨个后移1</span>
for(i = (size-1); i >= index;i--){
elementData[i+1] = elementData[i];
}
elementData[i+1] = element; <span style="color:#009900;">//插入该元素</span>
size++; <span style="color:#009900;">//数组当前容量+1</span>
}
else{
throw new IndexOutOfBoundsException("插入元素位置越界!!!");
}
}
<span style="color:#009900;">//想线性表末尾添加元素</span>
public void add(T element){
ensureCapacity(); <span style="color:#009900;">//确保线性表容量够</span>
elementData[size] = element;
size++;
}
<span style="color:#009900;">//删除线性表中指定位置元素</span>
public void delete(int index){
if(index >= 0 && index < size){
int i;
<span style="color:#009900;">//将要删除元素位置之后的元素挨个前移1,通过覆盖删除</span>
for(i = index+1;i < size;i++){
elementData[i-1] = elementData[i];
}
elementData[size-1] = null;
}
else{
throw new IndexOutOfBoundsException("所要删除元素位置越界!!!");
}
}
<span style="color:#009900;">//删除指定元素</span>
public void delete(T value){
int index = this.getIndexByValue(value);
if(index != -1){
this.delete(index);
}
else{
System.out.println("您要删除的元素并不存在");
System.exit(0);
}
size--;
}
<span style="color:#009900;">//判断线性表是否为空</span>
public boolean isEmpty(){
boolean b = false;
if(this.length() != 0){
b = true;
}
return b;
}
<span style="color:#009900;">//清空线性表</span>
public void clear(){
for(Object o:elementData){
o = null;
}
size = 0;
}
<span style="color:#009900;">//显示线性表中所有元素</span>
public void view(){
System.out.print("当前线性表中元素为:");
for(int i = 0;i < size;i++){
System.out.print(elementData[i] + " ");
}
System.out.print("\n");
}
<span style="color:#009900;">//扩充线性表容量</span>
public void ensureCapacity(){
while((size+1) > capacity){
capacity= capacity * 2; <span style="color:#009900;">//线性表容量每次增大一倍</span>
elementData = Arrays.copyOf(elementData, capacity);
}
}
public static void main(String[] args) {
Sequence<String> sequence = new Sequence<>();
sequence.add("hello");
sequence.add("world");
sequence.add("java");
sequence.add("perfect");
sequence.view();
sequence.insert("haha", 1);
sequence.view();
System.out.println("索引为3的元素为:" + sequence.getElementByIndex(3));
System.out.println("字符串perfect的索引号为:" + sequence.getIndexByValue("perfect"));
sequence.delete("hello");
sequence.view();
sequence.clear();
System.out.println("clear之后线性表长度为:" + sequence.length());
}
}
三、链式存储结构
1、概念
链式存储结构的线性表(简称为链表)采用一组任意的存储单元存放线性表中的数据元素。链式存储结构的线性表不是按线性的逻辑顺序来保存数据元素,它需要在每个数据元素里保存一个引用下一个数据元素的引用。
节点 = 数据元素 + 引用下一个节点的引用 + 引用上一个节点的引用
2、单链表基本操作
建立单链表方法:1头插法建表 2尾插法建表
查找操作:1按index查找指定数据元素 2在链表中查找指定的数据元素的index
插入操作:在第index个索引处插入元素
删除操作:删除第index个节点
3、单链表具体实现
public class LinkList<T>{
<span style="color:#009900;">//定义Node节点</span>
private class Node{
private T data;
private Node next;
public Node(){
}
public Node(T element,Node next){
this.data = element;
this.next = next;
}
}
<span style="color:#009900;">//成员变量</span>
private Node header; <span style="color:#009900;">//头节点</span>
private Node tail; <span style="color:#009900;">//尾节点</span>
private int size = 0; <span style="color:#009900;">//链表长度</span>
public LinkList(){
header = null;
tail = header;
}
public LinkList(T element){
header = new Node(element, null);
tail = header;
}
<span style="color:#009900;">//获取链表中指定索引处的元素</span>
public T get(int index){
return this.getNodeByIndex(index).data;
}
<span style="background-color: rgb(0, 153, 0);">//获取链表中指定索引处Node</span>
public Node getNodeByIndex(int index){
this.checkBorder(index);
Node currentNode = header;
for(int i = 0;i < size && currentNode != null;i++,currentNode = currentNode.next){
if(i == index){
return currentNode;
}
}
return null;
}
<span style="background-color: rgb(255, 255, 255);"><span style="color:#009900;">//向指定索引处插入元素</span></span>
public void insert(T element,int index){
this.checkBorder(index);
if(index == 0){
this.addAtHeader(element);
}
else{
Node prevNode = this.getNodeByIndex(index-1);//获取插入位置的前向Node
prevNode.next = new Node(element,prevNode.next);
}
size++;
}
<span style="color:#009900;">//删除指定索引处Node</span>
public T delete(int index){
this.checkBorder(index);
Node del = null;
//删除的是header
if(index == 0){
del = header;
header = header.next;
}
else{
Node prevNode = this.getNodeByIndex(index);
del = prevNode.next;
prevNode.next = del.next; //将prevNode的后向Node设置为del.next
del.next = null;
}
size--;
return del.data;
}
<span style="color:#009900;">//头插法向链表中添加元素</span>
public void addAtHeader(T element){
header = new Node(element,header);//将新添加的Node的next设置为原先的header,然后将新的Node设置为新的header
if(tail == null){
tail = header;
}
size++;
}
<span style="color:#009900;">//尾插法</span>
public void add(T element){
//链表为空的情况
if(header == null){
header = new Node(element, null);
tail = header;
}
else{
tail.next = new Node(element, null); //将tail节点的next设置为new Node
tail = tail.next; //将new Node设置为tail
}
size++;
}
<span style="color:#009900;">//遍历整个链表</span>
public void view(){
Node currentNode = header;
System.out.print("当前链表元素:");
while(currentNode != null){
System.out.print(currentNode.data + " ");
currentNode = currentNode.next;
}
System.out.println("");
}
<span style="color:#009900;">//检测索引是否越界</span>
private void checkBorder(int index){
if(index < 0 || index > size-1){
throw new IndexOutOfBoundsException("链表索引已越界");
}
}
public int length(){
return this.size;
}
public static void main(String args[]){
LinkList<String> linkList = new LinkList<>();
linkList.add("hello");
linkList.add("world");
linkList.addAtHeader("header");
System.out.println("当前链表长度为:" + linkList.length());
linkList.view();
System.out.print("插入test之后,");
linkList.insert("test",2);
linkList.view();
linkList.delete(2);
System.out.print("删除索引2处元素后,");
linkList.view();
System.out.println("索引1处元素为:" + linkList.get(1));
}
}
4、双链表实现
public class DoubleLinkList<T> {
<span style="color:#009900;">//定义双向链表节点</span>
private class Node{
private T data;
private Node prev;
private Node next;
public Node(){
}
public Node(T element,Node prev,Node next){
this.data = element;
this.prev = prev;
this.next = next;
}
}
private Node header;
private Node tail;
private int size = 0;
public DoubleLinkList(){
header = null;
tail = null;
}
public DoubleLinkList(T element){
header = new Node(element,null,null);
tail = header;
size++;
}
<span style="color:#009900;">//获取链表长度</span>
public int length(){
return this.size;
}
<span style="color:#009900;">//检测index是否越界</span>
public void checkBorder(int index){
if(index < 0 || index > size-1){
throw new IndexOutOfBoundsException("链表索引已越界");
}
}
<span style="color:#009900;">//获取指定索引处Node</span>
public Node getNodeByIndex(int index){
checkBorder(index);//越界检测
if(index < size/2){
Node currentNode = header;
for(int i = 0;i < size/2;i++,currentNode = currentNode.next ){
if(i == index){
return currentNode;
}
}
}
else{
Node currentNode = tail;
for(int i = size-1;i >= size/2;i--,currentNode = currentNode.prev){
if(i == index){
return currentNode;
}
}
}
return null;
}
<span style="color:#009900;">//获取链表中指定索引处的元素值</span>
public T get(int index){
return this.getNodeByIndex(index).data;
}
<span style="color:#009900;">//根据元素值查找元素索引</span>
public int locate(T element){
Node currentNode = this.header;
for(int i = 0;i < size-1;i++,currentNode = currentNode.next){
if(currentNode.data.equals(element)){
return i;
}
}
return -1;
}
<span style="color:#009900;">//向链表中以尾插法添加元素</span>
public void add(T element){
if(size == 0){
header = new Node(element,null,null);
tail = header;
}
else{
Node newNode = new Node(element,tail,null);
tail.next = newNode;
tail = newNode;
}
size++;
}
<span style="color:#009900;">//头插法向链表添加元素</span>
public void addAtHeader(T element){
if(size == 0){
header = new Node(element,null,null);
tail = header;
}
else{
Node newNode = new Node(element,null,header);
header.prev = newNode;
header = newNode;
}
size++;
}
<span style="color:#009900;">//根据索引插入元素</span>
public void insert(T element,int index){
this.checkBorder(index);
Node prevNode = this.getNodeByIndex(index-1);
Node nextNode = this.getNodeByIndex(index);
Node insertNode = new Node(element, prevNode, nextNode);
nextNode.prev = insertNode;
prevNode.next = insertNode;
size++;
}
<span style="color:#009900;">//根据索引删除元素</span>
public void delete(int index){
this.checkBorder(index);
Node prevDelNode = this.getNodeByIndex(index-1);
Node nextDelNode = this.getNodeByIndex(index+1);
prevDelNode.next = nextDelNode;
nextDelNode.prev = prevDelNode;
size--;
}
<span style="color:#009900;">//遍历链表中元素</span>
public void view(){
System.out.print("当前链表中元素为:");
for(int i = 0;i < size;i++){
System.out.print(this.get(i) + " ");
}
System.out.println();
}
public static void main(String[] args) {
DoubleLinkList<String> doubleLinkList = new DoubleLinkList<>();
doubleLinkList.add("hello");
doubleLinkList.add("world");
doubleLinkList.insert("test", 1);
doubleLinkList.addAtHeader("first");
doubleLinkList.view();
System.out.println("索引为0处的元素值为:" + doubleLinkList.get(0));
System.out.println("test字符串在链表中索引号为: " + doubleLinkList.locate("test"));
doubleLinkList.delete(1);
System.out.print("删除索引号为1元素后,");
doubleLinkList.view();
}
}
注:本文部分内容参考自《疯狂Java程序员的基本修养》和《数据结构(C语言版)》