数据结构(Java语言描述)

第一章 概述

四个问题(为什么要学习数据结构):

1. 计算机如何高效且方便地表示和组织是数据?
2. 计算机如何存储数据?
3. 我们如何操作数据?可以实现哪一些操作?对待同一问题的解决办法的评判标准?
4. 如何选择某一问题的最优解?
  1. 数据结构的作用和意义

优秀的数据结构与算法是无数计算机前辈在不断实践中总结出来处理问题的经验,学习数据结构与算法,会让我们站在巨人的肩膀上,更快更好的处理相应的问题。

计算机处理问题时,我们必须为其设定好程序,必须告诉计算机如何去做。

接下来给出数据结构的定义:数据结构是一门研究非数值计算的程序设计问题中计算机的操作对象以及他们之间的关系及操作的学科。 下面我们通过两个例子解释一下什么是非数值计算。

数据结构转换成json java 设置键的顺序_线性表

思考 我们把一个参赛项表示为图中的一个顶点,两个顶点中间有连线代表两个项目之间不能同时举行。

数据结构转换成json java 设置键的顺序_线性表_02


1.1数据结构的基本概念(数据、数据元素、数据对象、数据结构、数据类型)
数据:信息的载体,是对客观事物的符号表示。
数据元素:数据的基本单位,由一个或者多个数据项组成。
数据对象:具有相同特征的数据元素的集合。
数据结构:Data Structure,是数据及数据元素的组织形式。(集合,线性结构,树形结构,图形[网状]结构)。

数据的逻辑结构:Logic Structure,是从具体问题抽象出来的数学模型。独立于计算机,是数据本身固有的特性。
从逻辑上可以分为线性结构和非线性结构。
数据的物理结构:Physical Structure,又称数据的存储结构,分为顺序结构和链式结构。

数据结构转换成json java 设置键的顺序_java_03

数据结构转换成json java 设置键的顺序_java_04

1.2面向对象的数据结构表示

Java面向对象基础

1. 类的声明与实例化
2. 类成员的定义与使用
3. 抽象类
4. 泛型类
5. 面向对象的抽象数据类型
 
数据结构研究的是数据对象内部个数据元素之间逻辑关系问题,他不关心数据的具体类型,因此数据结构本身是
抽象的。

传统抽象数据类型定义
ADT 抽象数据类型名{
	数据对象D:<数据对象的定义>
	数据关系S:<数据关系的定义>
	基本操作P:<基本操作的定义>
}

eg:一个集合的抽象数据类型
ADT Set{
	数据元素: ai 属于同一数据对象,i= 1,2,3,4,...... n(n >= 0)
	逻辑结构: <ai,ai-1> | i=1,2,3,4, ...... ,n(n >= 0),a1无前驱,an无后继
	基本操作: InitSet()
			 Length()
			 Insert(i,x)
			 Delete()
			 ......
}ADT Set

Java泛型类表示的抽象数据类型格式
[访问修饰符] class抽象数据类型名<类型参数列表>
{
	[访问修饰符] 数据类型 数据对象;// 数据对象定义
	[访问修饰符] 返回值类型 基本操作1(参数列表){
		// 基本操作1的定义
	}
	
	// 其他基本操作
}

eg:一个字典的抽象数据类型
public class Dictionary<K,V>{
	// 数据对象的定义:词典由原文词汇表和译文词汇表组成
	public K[] keys;
	public V[] values;
	public int n;
	// 基本操作: 词典提供初始化,添加新词,删除词条,翻译等操作
	
	public Dictionary (int max){
		// 初始化操作的定义
	}
	
	public void append(K k, V v){
		// 添加新词的定义
	}
	
	public boolean delete(K k){
		// 删除词条的定义
	}
	
	public V translate(K k){
		// 翻译操作的定义
	}
	
	// 其他操作定义
}

数据结构转换成json java 设置键的顺序_java_05

1.3算法和算法分析

算法 + 数据结构 = 程序

算法其实就是为了解决某一问题而采取的方法和步骤的准确完整描述,他是一个有穷的规则序列,这些规则决定了
解决某一特定问题的一系列运算。

算法的特征
1. 有穷性
2. 确定性
3. 可行性
4. 输入
5. 输出

评价一个算法优劣的标准
1. 正确性
2. 可读性
3. 健壮性
4. 运行时间
5. 占用空间

算法效率的度量
1. 时间复杂度
	一个程序的运行时间是指程序从开始到结束所需要的时间。影响程序运行时间的因素是多方面的(机器运行速
	度、编译程序产生的目标代码质量、数据的输入等)。【选中最基本的一条语句,看他执行了多少次】
2. 空间复杂度
	空间复杂度是对一个算法在运行过程中临时占用存储空间大小的度量。
一.	填空题
1.数据的物理结构包括 顺序结构 的表示和存储和 链式结构 的表示和存储。
2.对于给定的n个元素,可以构造出的逻辑结构有(集合结构),(线性结构),(树型结构),(图型结构)四种。
3.一个算法具有5个特性:(有穷性)、(确定性)、(可行性),有零个或多个输入、有一个或多个输出。
4.抽象数据类型被形式地定义为(D,S,P),其中D是(数据元素)的有限集合,S是D上的(关系)有限集合, P是对D的(基本操作)集合。
5.数据结构主要包括数据的(逻辑结构)、数据的(存储结构)和数据的(操作)这三个方面的内容。
6.一个算法的效率可分为(时间)效率和(空间)效率。
二.单项选择题
1.线性结构是数据元素之间存在一种( D  )。
A.一对多关系     B.多对多关系      C.多对一关系      D.一对一关系
2.数据结构中,与所使用的计算机无关的是数据的(   C  )结构。
A.存储      B.物理       C.逻辑       D.物理和存储
3.算法分析的目的是(  B   )。
A.找出数据结构的合理性                  B.分析算法的效率以求改进
C.研究算法中的输入和输出的关系     D.分析算法的易懂性和文档性
4.算法分析的两个主要方面是(   A  )。
A.空间复杂性和时间复杂性       B.正确性和简明性
C.可读性和文档性                    D.数据复杂性和程序复杂性
5.计算机算法指的是(   C  )。
A.计算方法                      B.排序方法
C.解决问题的有限运算序列        D.调度方法
6.从逻辑上可以把数据结构分为(   A  )。
A.线性结构和非线性结构       B.紧凑结构和非紧凑结构
C.动态结构和静态结构          D.内部结构和外部结构

第二章 线性表

4.1 线性表的逻辑结构
什么是线性表?		
线性表(Linear List)是n个元素的有限序列,可以表示成(a1,a2,a3,,,,ai,,,,an)。我们称n为线性表的长度,
n=0时,线性表为空表。ai是数据表中的元素,i是元素ai在线性表中的位序。

数据结构转换成json java 设置键的顺序_线性表_06

线性表有那些特点?
1. 线性表中必存在   第一元素
2. 线性表中必存在   最后元素
3. 除第一元素之外   均有前驱元素
4. 除最后元素之外   均有后继元素
线性表的基本操作
                                                               
初始化: 构造一个空的线性表
销毁: 销毁一个已经存在的线性表

(对数据 加工性操作)
插入: 在第i个位置之前插入一个新元素
删除: 删除第i个位置上的元素
更新: 更新或修改第i个位置上的元素

(引用型操作)
查找: 找出线性表中满足特定条件的元素的下标或位置
获取: 获取指定位置或者下标上的数据元素
判空: 判断线性表是否为空
求长度: 求出线性表里边个元素个数
遍历输出: 一次打印输出线性表中的内容
4.2 线性表的顺序表示和实现
线性表中存储的数据元素的数据类型是一样的,每个元素在内存中占用的内存空间也都是一样的。我们只需要知道
线性表的首地址,那么我们就是能直接拿到线性表中任意元素的内存地址。
LOC(ai)  =  LOC(a1)  + (i-1) * L   
LOC(ai)   第i个元素的内存地址
LOC(a1)   第一个元素的内存地址
L   L是每个元素占用的内存空间,比如说int类型 每个元素占用四个字节

数据结构转换成json java 设置键的顺序_java_07

数据结构转换成json java 设置键的顺序_java_08

数据结构转换成json java 设置键的顺序_数据_09

/**
* \* Created with IntelliJ IDEA.
* \* User: maomao
* \* Date: 2022/9/25
* \* Time: 9:24
* \* Description: 演示线性表的顺序结构以及其中方法的实现
* \
*/

public class SequenceList<T> {
   // 顺序表中一维数组的初始长度
   final int MAXSIZE = 10;
   // 存储数据元素的数组对象
   private T[] listArray;
   // 用于保存当前数组的长度
   private int length;

   public int getMAXSIZE() {
       return MAXSIZE;
   }

   public T[] getListArray() {
       return listArray;
   }

   // 默认初始化方法
   public SequenceList() {
       // 去内存里申请内存空间  按照默认的MAXSIZE去申请内存空间
       length = 0; // 线性表初始为空
       listArray =(T[]) new Object[MAXSIZE];
   }
   /**
    * 初始化方法
    * @param n 数组初始化的长度
    */
   public SequenceList(int n) {
       // 去内存里申请内存空间  按照参数n去申请内存空间
       if (n < 0) {
           System.out.println("eroor");
           System.exit(0);
       }
       length = 0; // 线性表初始为空
       listArray =(T[]) new Object[n];
   }
   /**
    * 向顺序表中添加数据
    * @param pos 添加元素的下标或者位置
    * @param obj 添加元素的值
    * @return
    */
   public boolean add(int pos, T obj) {
       if(pos < 0||pos >length-1){
           System.out.println("pos不合法");
           return false;
       }
       if(length==listArray.length){
// 要么扩容  要么报错
           T[] p =(T[]) new Object[length * 2];
           for(int i = 0;i<length;i++){
               p[i]=listArray[i];
           }
           listArray=p;
       }

       for(int i = length;i>pos;i--){
           listArray[i] = listArray[i-1];
       }

       listArray[pos] = obj;
       length++;
       return true;
   }
   /**
    * 删除顺序表中pos位置或者下标上的元素
    * @param pos 要删除元素的位置或者下标
    * @return
    */
   public T delete(int pos) {

       if(pos < 0||pos >length-1){
           System.out.println("pos不合法");
           return null;
       }

       if(length<=0){
           System.out.println("顺序表为空表");
           return null;
       }

       T t = listArray[pos];

       for(int i = pos;i<length-1;i++){
           listArray[i] = listArray[i+1];
       }
       length--;
       return t;
   }
   /**
    * 找出线性表中满足特定条件的元素的下标或位置
    * @param obj 特定元素
    * @return
    */
   public int find(T obj) {
       if(isEmpty()){
           System.out.println("顺序表为空");
           return -1;
       }
       for(int i = 0;i<length;i++){
           if(listArray[i].equals(obj)){
               return i;
           }
       }
       return -1;
   }
   /**
    * 获取指定位置或者下标上的数据元素
    * @param pos 指定位置或者下标
    * @return
    */
   public T getValue(int pos) {
       if (isEmpty()) {
           System.out.println("顺序表为空");
           return null;
       }
       if (pos < 0 || pos >= length) {
           System.out.println("pos不合法");
           return null;
       }
       return listArray[pos];
   }
   /**
    * 更新或修改第i个位置上的元素
    * @param pos 更新或修改元素的位置
    * @param obj 替换的值
    * @return
    */
   public boolean update(int pos, T obj) {
       if (isEmpty()) {
           System.out.println("顺序表为空");
           return false;
       }

       if (pos < 0 || pos >= length) {
           System.out.println("pos不合法");
           return false;
       }

       listArray[pos] = obj;
       return true;
   }
   /**
    * 判断线性表是否为空
    * @return
    */
   public boolean isEmpty() {
       return length==0;
   }
   /**
    * 求出线性表里边个元素个数
    * @return
    */
   public int getLength() {
       return length;
   }
   /**
    * 遍历输出
    */
   public void getSequenceList() {
       for (int i = 0; i < length; i++) {
           System.out.println(listArray[i]);
       }
   }

   /**
    * 合并两个顺表中的元素,按升序排列
    * @param LA 顺序表LA
    * @param LB 顺序表LB
    * @return 顺序表LC
    */
   public SequenceList<T> Merge_list(SequenceList<T> LA,SequenceList<T> LB) {
       SequenceList<T> LC = new SequenceList<>();
       // 分别指向la,lb,lc元素的位置
       int i =1, j=1 ,k=1;
       while(i<=LA.getLength()&&j<= LB.getLength()){
           if ((int)LA.getValue(i) <= (int)LB.getValue(j)) {
               LC.add(k,LA.getValue(i));
               j++;
           } else {
               LC.add(k,LB.getValue(j));
               i++;
           }
           k++;
       }

       while(i<=LA.getLength()){
           LC.add(k,LA.getValue(i));
           k++;
           i++;
       }

       while(j<=LB.getLength()){
           LC.add(k,LB.getValue(j));
           k++;
           j++;
       }
       return LC;
   }
}

数据结构转换成json java 设置键的顺序_java_10

顺序表的初始化

// 默认初始化方法 public SequenceList() { // 去内存里申请内存空间 按照默认的MAXSIZE去申请内存空间 length = 0; // 线性表初始为空 listArray =(T[]) new Object[MAXSIZE]; } /** * 初始化方法 * @param n 数组初始化的长度 */ public SequenceList(int n) { // 去内存里申请内存空间 按照参数n去申请内存空间 if (n < 0) { System.out.println("eroor"); System.exit(0); } length = 0; // 线性表初始为空 listArray =(T[]) new Object[n]; }

数据插入

数据结构转换成json java 设置键的顺序_java_11

/** * 向顺序表中添加数据 * @param pos 添加元素的下标或者位置 * @param obj 添加元素的值 * @return */ public boolean add(int pos, T obj) { if(pos < 0||pos >length-1){ System.out.println("pos不合法"); return false; } if(length==listArray.length){ // 要么扩容 要么报错 T[] p =(T[]) new Object[length * 2]; for(int i = 0;i<length;i++){ p[i]=listArray[i]; } listArray=p; } for(int i = length;i>pos;i--){ listArray[i] = listArray[i-1]; } listArray[pos] = obj; length++; return true; }

数据结构转换成json java 设置键的顺序_java_12

注意:

  1. pos指的是元素下标 pos的范围是 0<= pos <=length-1,length指的是原表长,或者listArray它的长度
  2. listArray一共可以存储listArray.length个元素,插入数据的时候一定要先判断listArray有没有存满
  3. 插入数据移动元素的时候,一定是从后往前移动元素
  4. 插入元素之后,顺序表长度记得+1
数据删除

数据结构转换成json java 设置键的顺序_线性表_13

/** * 删除顺序表中pos位置或者下标上的元素 * @param pos 要删除元素的位置或者下标 * @return */ public T delete(int pos) { if(pos < 0||pos >length-1){ System.out.println("pos不合法"); return null; } if(length<=0){ System.out.println("顺序表为空表"); return null; } T t = listArray[pos]; for(int i = pos;i<length-1;i++){ listArray[i] = listArray[i+1]; } length--; return t; }

顺序表的查找

/** * 找出线性表中满足特定条件的元素的下标或位置 * @param obj 特定元素 * @return */ public int find(T obj) { if(isEmpty()){ System.out.println("顺序表为空"); return -1; } for(int i = 0;i<length;i++){ if(listArray[i].equals(obj)){ return i; } } return -1; }

获取元素

/** * 获取指定位置或者下标上的数据元素 * @param pos 指定位置或者下标 * @return */ public T get(int pos) { if (isEmpty()) { System.out.println("顺序表为空"); return null; } if (pos < 0 || pos >= length) { System.out.println("pos不合法"); return null; } return listArray[pos]; }

修改元素

/** * 更新或修改第i个位置上的元素 * @param pos 更新或修改元素的位置 * @param obj 替换的值 * @return */ public boolean update(int pos, T obj) { if (isEmpty()) { System.out.println("顺序表为空"); return false; } if (pos < 0 || pos >= length) { System.out.println("pos不合法"); return false; } listArray[pos] = obj; return true; }

判空

/** * 判断线性表是否为空 * @return */ public boolean isEmpty() { return length==0; }

求顺序表的长度

/** * 求出线性表里边个元素个数 * @return */ public int getLength() { return length; }

遍历输出所有的元素

/** * 遍历输出 */ public void getSequenceList() { for (int i = 0; i < length; i++) { System.out.println(listArray[i]); } }

顺序表的应用

例: 有顺序表LA和LB,其元素均按照从小到大的升序排列,编写一个算法,将他们合并成一个顺序表LC,要求LC的元素也是从小到大 的升序。/** * 合并两个顺表中的元素,按升序排列 * @param LA 顺序表LA * @param LB 顺序表LB * @return 顺序表LC */ public SequenceList<T> Merge_list(SequenceList<T> LA,SequenceList<T> LB) { SequenceList<T> LC = new SequenceList<>(); // 分别指向la,lb,lc元素的位置 int i =1, j=1 ,k=1; while(i<=LA.getLength()&&j<= LB.getLength()){ if ((int)LA.getValue(i) <= (int)LB.getValue(j)) { LC.add(k,LA.getValue(i)); j++; } else { LC.add(k,LB.getValue(j)); i++; } k++; } while(i<=LA.getLength()){ LC.add(k,LA.getValue(i)); k++; i++; } while(j<=LB.getLength()){ LC.add(k,LB.getValue(j)); k++; j++; } return LC; }

数据结构转换成json java 设置键的顺序_算法_14

线性表的链式表示和实现

线性表的链式存储结构使用一组任意的存储单元来存放线性表的数据元素,这组存储单元可以是连续的,也可以是不连续
的。

那么,同学们请思考一下,对于其中的某一元素,如何找到他的下一个元素呢?

思考:顺序表怎么获取元素的直接后继元素的内存地址?链表又如何获取直接后继元素的内存地址?

单链表节点(单链表结点):单链表节点由两部分信息,第一部分是数据域(存储数据元素),第二部分是指针域(直接后
继元素的内存地址)。

~~~java
// 节点类定义
public class Node<T> {

   T data; //数据域
   Node<T> next;//指针域

   // 构造器
   public Node(Node<T> next) {
       this.next = next;
   }

   // 构造器
   public Node(T data, Node<T> next) {
       this.data = data;
       this.next = next;
   }

   public T getData() {
       return data;
   }

   public void setData(T data) {
       this.data = data;
   }

   public Node<T> getNext() {
       return next;
   }

   public void setNext(Node<T> next) {
       this.next = next;
   }
}

数据结构转换成json java 设置键的顺序_算法_15

linkList类,要有两成员变量,一个是指向头节点的指针,一个是length单链表的长度。

public class LinkList<T> {
    private Node<T> head;// 头指针
    private int length;  // 单链表长度
    // 构造器
    public LinkList() {
    }   
    // 获取表头结点的地址
    public Node<T> getHead() {
        return head;
    }
    // 在链表中插入一个元素
    public boolean add(T obj, int pos) {}
    // 删除一个元素
    public T remove(int pos) {}
    // 获取一个元素
    public T value(int pos) {}
    // 查找一个元素
    public int find(T obj) {}
    // 更新一个节点的值
    public boolean modify(T obj, int pos) {}
    // 判空
    public boolean isEmpty(){}
    // 求链表的长度
    public int size() {}   
    // 遍历输出链表
    public void nextOrder() {}   
    // 销毁一个链表
    public void clear() {}
}

数据结构转换成json java 设置键的顺序_算法_16

数据结构转换成json java 设置键的顺序_算法_17

假设存在一个链表:(a1,a2,a3,a4,s5,a6),那么它在内存中是怎样存储的?

数据结构转换成json java 设置键的顺序_java_18

添加新节点
1. 向尾部添加新节点
		创建一个新的节点a7
		让a6的指针域指向a7的内存地址
		a7的指针域置为null
2. 向中间添加新节点
		创建一个新的节点a7
		让a7的指针域指向a4的内存地址把a3的指针域赋值给a7的指针域
		把a3的指针域赋值成a7的地址
		
// 在链表中插入一个元素
    public boolean add(T obj, int pos) {
        // 判断pos是否合法,pos不能小于1 并且不能大于 length+1
        if (pos < 1 || pos > length + 1) {
            System.out.println("pos不合法输入");
            return false;
        }
        // 标记 目前查找到了第几个位置
        int num = 1;
        // 拿到头节点
        Node<T> p = head;
        // 通过头节点,拿到链表的第一个节点
        Node<T> q = head.next;
        while (num < pos) {
            p = q;
            q = q.next;
            num++;
        }
        p.next = new Node<T>(obj, q);
        length++;
        return true;
    }

数据结构转换成json java 设置键的顺序_数据结构_19

数据结构转换成json java 设置键的顺序_数据_20

删除元素
1. 在链表的尾部删除元素
2. 删除中间元素

// 删除一个元素
    public T remove(int pos) {
        if (isEmpty()) {
            System.out.println("链表为空,请先插入元素");
        }
        // 判断pos是否合法,pos不能小于1 并且不能大于 length+1
        if (pos < 1 || pos > length + 1) {
            System.out.println("pos不合法输入");
            return null;
        }
        int num = 1;
        // 拿到头节点
        Node<T> p = head;
        // 通过头节点,拿到链表的第一个节点
        Node<T> q = head.next;
        while (num < pos) {
            p = q;
            q = q.next;
            num++;
        }
        p.next = q.next;
        length--;
        return q.data;
    }

数据结构转换成json java 设置键的顺序_java_21

数据结构转换成json java 设置键的顺序_算法_22

单链表查找值
1. 判断链表是否为空
2. 引入头节点,保存节点p中
3. 循环判断p.data.equals(obj),如果为true,返回pos,否则,返回-1.
    
// 获取一个元素
    public T value(int pos) {
        // 判断链表是否为空
        if (isEmpty()) {
            System.out.println("链表为空,请先插入元素");
        }
        // 判断pos是否合法,pos不能小于1 并且不能大于 length+1
        if (pos < 1 || pos > length + 1) {
            System.out.println("pos不合法输入");
            return null;
        }
        int num = 1;
        Node<T> p = head.next;
        while (num < pos) {
            p = p.next;
            num++;
        }
        return p.data;
    }

数据结构转换成json java 设置键的顺序_算法_23

单链表查找第pos个节点的值
1. 判断链表是否为空
2. 判断pos是否合法输入
3. 循环并返回p.data

// 查找一个元素
    public int find(T obj) {
        // 判断链表是否为空
        if (isEmpty()) {
            System.out.println("链表为空,请先插入元素");
        }
        int num = 1;
        Node<T> p = head.next;
        while (p != null) {
            if (p.data.equals(obj) == false) {
                p = p.next;
                num++;
            }
            break;
        }
        if (p == null) {
            return -1;
        }
        return num;
    }

数据结构转换成json java 设置键的顺序_算法_24

单链表更新第pos个节点的值
1. 判断链表是否为空
2. 判断pos是否合法输入
3. 循环并修改p.data = obj

 // 更新一个节点的值
    public boolean modify(T obj, int pos) {
        // 判断链表是否为空
        if (isEmpty()) {
            System.out.println("链表为空,请先插入元素");
        }
        // 判断pos是否合法,pos不能小于1 并且不能大于 length+1
        if (pos < 1 || pos > length + 1) {
            System.out.println("pos不合法输入");
            return false;
        }
        int num = 1;
        Node<T> p = head.next;
        while (num < pos) {
            p = p.next;
            num++;
        }
        p.data = obj;
        return true;
    }

数据结构转换成json java 设置键的顺序_算法_25

完整实现:

public class LinkList<T> {
    private Node<T> head;// 头指针
    private int length;  // 单链表长度

    // 构造器
    public LinkList() {
        length = 0;
        head = new Node<T>(null);
    }

    // 获取表头结点的地址
    public Node<T> getHead() {
        return head;
    }

    // 在链表中插入一个元素
    public boolean add(T obj, int pos) {
        // 判断pos是否合法,pos不能小于1 并且不能大于 length+1
        if (pos < 1 || pos > length + 1) {
            System.out.println("pos不合法输入");
            return false;
        }
        // 标记 目前查找到了第几个位置
        int num = 1;
        // 拿到头节点
        Node<T> p = head;
        // 通过头节点,拿到链表的第一个节点
        Node<T> q = head.next;
        while (num < pos) {
            p = q;
            q = q.next;
            num++;
        }
        p.next = new Node<T>(obj, q);
        length++;
        return true;
    }

    // 删除一个元素
    public T remove(int pos) {
        if (isEmpty()) {
            System.out.println("链表为空,请先插入元素");
        }
        // 判断pos是否合法,pos不能小于1 并且不能大于 length+1
        if (pos < 1 || pos > length + 1) {
            System.out.println("pos不合法输入");
            return null;
        }
        int num = 1;
        // 拿到头节点
        Node<T> p = head;
        // 通过头节点,拿到链表的第一个节点
        Node<T> q = head.next;
        while (num < pos) {
            p = q;
            q = q.next;
            num++;
        }
        p.next = q.next;
        length--;
        return q.data;
    }

    // 获取一个元素
    public T value(int pos) {
        // 判断链表是否为空
        if (isEmpty()) {
            System.out.println("链表为空,请先插入元素");
        }
        // 判断pos是否合法,pos不能小于1 并且不能大于 length+1
        if (pos < 1 || pos > length + 1) {
            System.out.println("pos不合法输入");
            return null;
        }
        int num = 1;
        Node<T> p = head.next;
        while (num < pos) {
            p = p.next;
            num++;
        }
        return p.data;
    }

    // 查找一个元素
    public int find(T obj) {
        // 判断链表是否为空
        if (isEmpty()) {
            System.out.println("链表为空,请先插入元素");
        }
        int num = 1;
        Node<T> p = head.next;
        while (p != null) {
            if (p.data.equals(obj) == false) {
                p = p.next;
                num++;
            }
            break;
        }
        if (p == null) {
            return -1;
        }
        return num;
    }

    // 更新一个节点的值
    public boolean modify(T obj, int pos) {
        // 判断链表是否为空
        if (isEmpty()) {
            System.out.println("链表为空,请先插入元素");
        }
        // 判断pos是否合法,pos不能小于1 并且不能大于 length+1
        if (pos < 1 || pos > length + 1) {
            System.out.println("pos不合法输入");
            return false;
        }
        int num = 1;
        Node<T> p = head.next;
        while (num < pos) {
            p = p.next;
            num++;
        }
        p.data = obj;
        return true;
    }

    // 判空
    public boolean isEmpty(){
        return this.length==0;
    }

    // 求链表的长度
    public int size() {
        return this.length;
    }

    // 遍历输出链表
    public void nextOrder() {
        Node<T> p = this.head.next;
        while (p != null) {
            System.out.println(p.data);
            p = p.next;
        }
    }

    // 销毁一个链表
    public void clear() {
        this.head = null;
        this.length = 0;
    }

    public static void main(String[] args) {
        LinkList<Integer> L = new LinkList<>();
        int i;
        int[] a = {23, 34, 45, 56, 67, 78};
        for (i = 0; i < a.length; i++) {
            L.add(a[i], i + 1);
        }
        System.out.print("单链表的数据为:");

        // 向链表里边添加一个数据
        L.add(89, 7);
        L.add(89, 5);
        // 向链表里边删除一个数据
        L.remove(3);
        // 打印输出链表
        L.nextOrder();
    }
}
2.4 循环链表
循环单链表:

	最后一个节点的指针域指向head节点

循环双链表:

	最后一个节点的指针域2指向head节点
	head节点的指针域1指向最后一个节点

数据结构转换成json java 设置键的顺序_数据结构_26

2.5 链表的应用
链表的应用:将两个有序链表合并成一个有序链表。
思路: 设LC是合并后的链表,我们无需为LC申请新的内存空间,可以直接利用两个链表里原有的节点链接成一个新表即可。

设三个链表LA,LB,LC,再来三个指针pa,pb,pc,其中pa,pb分表代表LA、LB中当前带比较插入的节点,pc指向的是当前LC中最后一个节点。然后一次比较pa和pb指向的两个节点,把小的放入pc指向的节点中。

数据结构转换成json java 设置键的顺序_数据_27


数据结构转换成json java 设置键的顺序_算法_28


数据结构转换成json java 设置键的顺序_数据_29

练习题:

一.填空题
1.线性表的两种存储结构分别为(顺序存储)和(链式存储)。
2.顺序表中,逻辑上相邻的元素,其物理位置    一定      相邻。在单链表中,逻辑上相邻的元素,其物理位置    不
一定       相邻。
3.若经常需要对线性表进行插入和删除操作,则最好采用(链式)存储结构,若线性表的元素总数基本稳定,且很少进行插
入和删除操作,但要求以最快的速度存取线性表中的元素,则最好采用(顺序)存储结构。
4.在顺序表中等概率下插入或删除一个元素,需要平均移动  (n/2) 元素,具体移动的元素个数与  (插入或删除位置) 
    有关。
5.在带头结点的非空单链表中,头结点的存储位置由  (head头指针)  指示,首元素结点的存储位置由   (head.next) 
    指示,除首元素结点外,其它任一元素结点的存储位置由 (其直接前驱) 指示。
6.已知L是带头结点的单链表,且p结点既不是首元素结点,也不是尾元素结点。按要求从下列语句中选择合适的语句序列。

a. 在p结点后插入s结点的语句序列是:                                  。

s.next=p.next;    p.next=s;

b. 在p结点前插入s结点的语句序列是:                         。

q=head;   while(q.next!=p)  q=q.next;    s.next=p;  q.next=s;

c. 在表首插入s结点的语句序列是:                                。

s.next=head.next;    head.next=s;

d. 在表尾插入s结点的语句序列是:                               。 

while(p.next!=null)  p=p.next;  s.next=null;   p.next=s;

二.单项选择题
1.线性表是(  A   )。
A.一个有限序列,可以为空         B.一个有限序列,不能为空
C.一个无限序列,可以为空         D.一个无限序列,不能为空
2.带头结点的单链表L为空的判定条件是(  B   )。
A.head==null                        B.head .next==null               
C.head .next==L                      D.head!=null
3.在表长为n的单链表中,算法时间复杂度为O(n)的操作为(  D   )。
A.删除p结点的直接后继结点       B.在p结点之后插入一个结点
C.删除表中第一个结点                 D.查找单链表中第i个结点
4.在表长为n的顺序表中,算法时间复杂度为O(1)的操作为(  C   )。
A.在第i个元素前插入一个元素      B.删除第i个元素    
C.在表尾插入一个元素                  D.查找其值与给定值相等的一个元素
5.设单链表中指针p指向结点ai,若要删除ai之后的结点,则需修改指针的操作为( B  )。
A.p=p.next                       B.p.next=p.next.next
C.p=p.next.next                   D.next=p

第三章 栈和队列

3.1 顺序栈
栈:栈是限定仅在表尾部进行插入和删除操作的线性表。允许插入和删除的一端称为栈顶(top),另一端则称为栈底
(bottom),不含任何数据元素的栈为空栈。

栗子:有一座独木桥,在桥上,一次只允许一个人通过,当后面有人时,前面的人不能转身返回,只能走到底。那么我们假
设,桥的另一端没有路(或者说是不能通过),只能原路返回,那么这一行人返回的顺序是怎样的?

最后一个先下桥,然后倒数第二个,最后才是第一个上桥的人。

对于这样的过程,我们把这一行人,当作数据元素,并且元素之间存在序偶关系,这种先进后出的线性表结构我们称为栈。

数据结构转换成json java 设置键的顺序_数据结构_30

a1 为栈底元素,an为栈顶元素。
栈中元素的进栈顺序为 a1,a2,a3,...,an
栈中元素的出栈顺序为an,...,a3,a2,a1

所以,栈被称为后进先出(LIFO)的线性表(Last in First out)

栈有两个操作:入栈和出栈。入栈和出栈操作的都是栈顶元素。所以栈顶的位置随着元素的插入和删除而变化,为此我们需
要一个指向栈顶的指针来指示栈顶的当前位置。

数据结构转换成json java 设置键的顺序_算法_31

元素入栈和出栈过程

数据结构转换成json java 设置键的顺序_数据_32

栈的基本操作
1. 初始化----头造一个空的栈
2. 入栈----在栈顶位置插入一个新元素
3. 出栈----删除栈顶元素
4. 获取----取栈顶元素
5. 判空----判断当前栈是否为空
6. 求长度----求出栈中元素的个数
7. 正序遍历----一次访问栈中每个元素并输出
8. 销毁----销毁一个已存在的栈

数据结构转换成json java 设置键的顺序_线性表_33

栈的分类:顺序栈和链栈

顺序栈:利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素。把数组中下标为0的一端作为栈底,为了指示栈
中元素的位置,我们定义变量top来指示栈顶元素在顺序栈中的位置,top为整型。

顺序栈的泛型类定义如下:


public class SequenceStack<T> {

    final int MaxSize = 10; //默认申请数组的初始化容量
    private T[] stackArray;
    private int top;


    public SequenceStack() {
    }

    public SequenceStack(int n) {
    }

    //在栈顶插入一个新元素
    public void push(T obj) {

    }

    // 删除栈顶元素
    public T pop() {
        return null;
    }

    //取栈顶数据元素
    public T getHead() {
        return null;
    }

    //判断当前栈是否为空
    public boolean isEmpty() {
        return false;
    }

    //求出栈中数据元素的个数
    public int size() {
        return this.top;
    }

    //依次访问栈中的每个元素
    public void nextOrder() {

    }

    //销毁一个栈
    public void clear() {

    }
}

数据结构转换成json java 设置键的顺序_算法_34

1.top:为指针,指向栈顶元素的位置
top的初始值为-1,指向栈底,而这个top=-1也可以作为栈空的标志。

数据结构转换成json java 设置键的顺序_数据_35

2.顺序栈的基本操作(栈的初始化,入栈,出栈,取栈顶元素,判栈空操作,求栈长度,遍历栈,清空栈)
栈的初始化:为栈分配一个数组,初始化栈的长度以及栈顶指针。

    public SequenceStack() {
        top = -1;
        stackArray = (T[]) new Object[MaxSize];
    }

    public SequenceStack(int n) {
        if (n < 0) {
            System.out.println("数组初始化长度要大于零");
            System.exit(1);
        }
        top = -1;
        stackArray = (T[]) new Object[n];
    }

数据结构转换成json java 设置键的顺序_线性表_36

入栈:栈顶指针上移一位,插入数据元素。
   
   //在栈顶插入一个新元素
    public void push(T obj) {
//        判断是否满栈,如果是满栈,则将栈扩容到当前容量的2倍
        if (top == stackArray.length - 1) {
            T[] p =(T[]) new Object[top * 2 + 2];
            for (int i = 0; i <= top; i++) {
                p[i] = stackArray[i];
            }
            stackArray = p;
        }
        top++;
        stackArray[top] = obj;
    }

数据结构转换成json java 设置键的顺序_线性表_37

出栈:栈顶指针下移一位。

    // 删除栈顶元素
    public T pop() {

//      判断栈是否为空
        if (top == -1) {
            System.out.println("当前栈中数据已空,无需删除");
            return null;
        }
        top--;
        return stackArray[top+1];
    }

数据结构转换成json java 设置键的顺序_数据结构_38

//取栈顶数据元素
    public T getHead() {
        //      判断栈是否为空
        if (top == -1) {
            System.out.println("当前栈中数据已空,无需删除");
            return null;
        }
        return stackArray[top];
    }

数据结构转换成json java 设置键的顺序_数据结构_39

完整实现

public class SequenceStack<T> {

    final int MaxSize = 10; //默认申请数组的初始化容量
    private T[] stackArray;
    private int top;


    public SequenceStack() {
        top = -1;
        stackArray = (T[]) new Object[MaxSize];
    }

    public SequenceStack(int n) {
        if (n < 0) {
            System.out.println("数组初始化长度要大于零");
            System.exit(1);
        }
        top = -1;
        stackArray = (T[]) new Object[n];
    }

    //在栈顶插入一个新元素
    public void push(T obj) {
//        判断是否满栈,如果是满栈,则将栈扩容到当前容量的2倍
        if (top == stackArray.length - 1) {
            T[] p =(T[]) new Object[top * 2 + 2];
            for (int i = 0; i <= top; i++) {
                p[i] = stackArray[i];
            }
            stackArray = p;
        }
        top++;
        stackArray[top] = obj;
    }

    // 删除栈顶元素
    public T pop() {

//      判断栈是否为空
        if (top == -1) {
            System.out.println("当前栈中数据已空,无需删除");
            return null;
        }
        top--;
        return stackArray[top+1];
    }

    //取栈顶数据元素
    public T getHead() {
        //      判断栈是否为空
        if (top == -1) {
            System.out.println("当前栈中数据已空,无需删除");
            return null;
        }
        return stackArray[top];
    }

    //判断当前栈是否为空
    public boolean isEmpty() {

        return top==-1;
    }

    //求出栈中数据元素的个数
    public int size() {
        return this.top+1;
    }

    //依次访问栈中的每个元素
    public void nextOrder() {
        for (int i = 0; i < top+1; i++) {
            System.out.println(stackArray[i]);
        }
    }

    //销毁一个栈
    public void clear() {
        top = -1;
    }
}
3.3 顺序队列
队列:元素的添加在表的一端进行,元素的删除在表的另一端进行的线性表。允许插入的一端为队尾,允许删除的一端称为
对头。向队中添加元素叫入队,从队中删除元素叫出队。队列是一种先进先出的线性表(FIFO)。

队列的基本操作:
1.初始化:构造一个空队列
2.入队:在队列尾部插入新元素
3.出队:删除队列对头元素
4.获取队头:取队列队头元素
5.求长度:求出队列中的数据元素的个数
6.判空:判断当前队列是否为空
7.正序遍历:依次访问队列中每一个元素并输出
8.销毁:销毁一个已经存在的队列

和顺序栈相似,队列也可以用简单的一维数组表示。其下标下界为0,上界为n-1.另外还需要使用两个指针,分别指示队头
元素和队尾元素。

数据结构转换成json java 设置键的顺序_算法_40

数据结构转换成json java 设置键的顺序_线性表_41

入队出队示流程
1.空队列 front = rear = 0
2.入队列 rear += 1
3.出队列 front += 1    

问题:由于队列的入队和出队是在两端随着元素的不断插入、删除进行的,两个指针同时会向后移动,队列会很快移动到队
尾,发生溢出,而前边的空闲空间无法使用。怎么解决呢?同学们有没有好的办法。

数据结构转换成json java 设置键的顺序_算法_42

问题:由于队列的入队和出队是在两端随着元素的不断插入、删除进行的,两个指针同时会向后移动,队列会很快移动到队
尾,发生溢出,而前边的空闲空间无法使用。

方法一:

每次删除一个元素后,将整个队列向前移动一个单元,保持队列头总是固定在数组的第一个存储单元。
思考:我们每次删除元素,都要进行一次循环,移动队列中的所有元素向前移动一个内存单元。这样子的话对系统的伤害是
不是就直接拉满了?

方法二:循环链表

将顺序队列首尾相连,当队尾指针rear达到队尾时,如果还有数据元素需要入队,并且数组的第0个位置还空闲着,队尾指
针指向数组的0端。当队头指针达到front数组的下限时,如果还有数据元素出队,队头指针指向数组的0端。

这样子,出队元素空出的空间可被重新利用,除非整个队列全部被占用,否则不会发生溢出。

数据结构转换成json java 设置键的顺序_线性表_43

顺序循环队列泛型类:
public class sequenceQueue<T> {

    final int MaxSize = 10; // 申请数组的默认最大长度
    private T queueArray[]; // 模拟队列
    private int front, rear; // front 队头指针  rear 队尾指针

    // 构造一个空队列
    public sequenceQueue() {
    }

    // 入队
    public void EnQueue(T obj) {

    }

    // 出队
    public T DeQueue() {
        return null;
    }

    // 取队头元素
    public T getHead() {
        return null;
    }

    // 求出当前队列数据元素的个数
    public int size() {
        return 0;
    }

    // 判断当前队列是否为空
    public boolean isEmpty() {
        return false;
    }

    // 依次访问队列中的每一个元素并输出
    public void nextOrder() {
        
    }
    
    // 销毁一个已存在的队列
    public void clear() {
        
    }
}

数据结构转换成json java 设置键的顺序_线性表_44

循环队列示意图:

数据结构转换成json java 设置键的顺序_线性表_45

循环队列空对列和满队列的判断

如果此时再增加一个元素,那么队列将被填满元素,队尾指针将和队头指针重合,此时rear ==front .但是单纯的rear 
== front并不足以判断队列的状态。
那么我们一般采取两种解决办法:

一、设定一个标志位flag,初始为0,队列中增加一个元素,flag就增加1,队列中每出队一个元素,就减1.再结合rear 
== front就可以判断队列的状态了。

二、再循环队列中少用一个存储空间,约定队尾指针+1 = 队头指针表示队列已满。队头指针+1 = 队尾指针表示队列已
空。

数据结构转换成json java 设置键的顺序_算法_46

入队:
// 入队时,队尾指针+1,队头指针不移动
    public void EnQueue(T obj) {
        // 判断队列是否已满,队列已满,将队列容量扩大至原来的2倍
        if ((rear + 1) % queueArray.length == front) {
            T[] p = (T[]) new Object[queueArray.length * 2];
            if (rear == ((T[]) queueArray).length - 1) {
                for (int i = 0; i <= rear; i++) {
                    p[i] = queueArray[i];
                }
            } else {
                int i, j=1;
                for (i = front + 1; i < queueArray.length; i++,j++) {
                    p[j] = queueArray[i];
                }
                for (i = 0; i <= rear; i++,j++) {
                    p[j] = queueArray[i];
                }
                front = 0;
                rear = queueArray.length-1;
            }
            queueArray = p;
        }
        rear = (rear + 1) % queueArray.length;
        queueArray[rear] = obj;
    }

数据结构转换成json java 设置键的顺序_数据_47

完整实现:
public class sequenceQueue<T> {

    final int MaxSize = 10; // 申请数组的默认最大长度
    private T queueArray[]; // 模拟队列
    private int front, rear; // front 队头指针  rear 队尾指针

    // 构造一个空队列
    public sequenceQueue() {
        front = rear = 0;
        queueArray = (T[]) new Object[MaxSize];
    }

    // 入队时,队尾指针+1,队头指针不移动
    public void EnQueue(T obj) {
        // 判断队列是否已满,队列已满,将队列容量扩大至原来的2倍
        if ((rear + 1) % queueArray.length == front) {
            T[] p = (T[]) new Object[queueArray.length * 2];
            if (rear == ((T[]) queueArray).length - 1) {
                for (int i = 0; i <= rear; i++) {
                    p[i] = queueArray[i];
                }
            } else {
                int i, j=1;
                for (i = front + 1; i < queueArray.length; i++,j++) {
                    p[j] = queueArray[i];
                }
                for (i = 0; i <= rear; i++,j++) {
                    p[j] = queueArray[i];
                }
                front = 0;
                rear = queueArray.length-1;
            }
            queueArray = p;
        }
        rear = (rear + 1) % queueArray.length;
        queueArray[rear] = obj;
    }

    // 出队 删除元素时,队头指针front后移,而队尾指针rear不动
    public T DeQueue() {
        if (isEmpty()) {
            System.out.println("队列已空,无法读取元素");
            return null;
        }
        front = (front + 1) % queueArray.length;
        return queueArray[front];
    }

    // 取队头元素
    public T getHead() {
        if (isEmpty()) {
            System.out.println("队列已空,无法读取元素");
            return null;
        }

        return queueArray[(front+1) % queueArray.length];
    }

    // 求出当前队列数据元素的个数
    public int size() {
        return (rear - front + queueArray.length) % queueArray.length;
    }

    // 判断当前队列是否为空
    public boolean isEmpty() {
        return front == rear;
    }

    // 依次访问队列中的每一个元素并输出
    public void nextOrder() {
        int i, j = front;
        for (i = 0; i <= size(); i++) {
            j = (j + 1) % queueArray.length;
            System.out.println(queueArray[j]);
        }
    }

    // 销毁一个已存在的队列
    public void clear() {
        front = rear = 0;
    }
}
3.4 链队列
链队列:      
用链表表示的队列为链队列。链队列不存在假溢出的情况,下面给大家介绍的是一般的队列(非循环)。一个链队列需要两
个分别指示队头和队尾的指针才能唯一确定。

数据结构转换成json java 设置键的顺序_数据结构_48

public class LinkQueue<T> {
    private Node<T> front , rear;
    private int length;

    // 构造一个空的队列
    public LinkQueue() {
    }

    // 在队列的队尾插入一个新元素
    public void EnQueue() {

    }

    // 删除队列队头元素
    public T DeQueue() {
        return null;
    }

    // 取队列头元素
    public T getHead() {
        return null;
    }

    // 求出队列中数据元素的个数
    public int size() {
        return length;
    }

    // 判断当前队列是否为空
    public void isEmpty() {

    }

    // 依次访问队列中每个元素并输出
    public void nextOrder() {

    }

    // 销毁一个已存在的队列
    public void clear() {

    }
}

数据结构转换成json java 设置键的顺序_数据_49

完整实现:

public class LinkQueue<T> {
    private Node<T> front , rear;
    private int length;

    // 构造一个空的队列
    public LinkQueue() {
        length = 0;
        front = rear = new Node<T>(null);
    }

    // 在队列的队尾插入一个新元素
    public void EnQueue(T obj) {
        length++;
        rear = rear.next;
        rear.next = new Node<>(obj, null);
    }

    // 删除队列队头元素
    public T DeQueue() {
        if (isEmpty()) {
            System.out.println("队列已空,无法出队");
            return null;
        }
        Node<T> p = front.next;
        T x = p.data;
        front.next = p.next;
        length--;
        if (front.next == null) {
            rear = front;
        }
        return x;
    }

    // 取队列头元素
    public T getHead() {
        if (isEmpty()) {
            System.out.println("队列已空,无法出队");
            return null;
        }
        return front.next.data;
    }

    // 求出队列中数据元素的个数
    public int size() {
        return length;
    }

    // 判断当前队列是否为空
    public boolean isEmpty() {
        return front.next == null;
    }

    // 依次访问队列中每个元素并输出
    public void nextOrder() {
        Node<T> p = front.next;
        while (p != null) {
            System.out.println(p.data);
            p = p.next;
        }
    }

    // 销毁一个已存在的队列
    public void clear() {
        front.next = rear.next=null;
    }
}

第四章 串

串的基本概念:
串(或字符串),是由零个或多个字符组成的有限序列。一般记为:             S=' a1a2a3a4a5....an '  (n>=0)

其中,s是串的名字,用单引号括起来的是串的值,串中字符的个数n称为串的长度。零个字符的串称为空串,长度为0.

子串:串中任意个字符组成的子序列称为该串的子串。
主串:包含子串的串。
字符位置:字符在序列中的序号。
子串位置:子串在主串中的位置则以子串的第一个字符在主串中的位置来表示。
串相等:当且仅当这两个串的值是相等的,即只有两个串的长度相等,并且各个位置的字符串都相等时才相等。
注意:在描述串时,要求串的值必须用一对单引号括起来,但单引号本身不属于串,他的作用是为了避免与变量名或常量混淆。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1qvq4xQS-1665197015121)(数据结构(Java语言描述).assets/image-20220930213551890.png)]

~~~java
   串的基本操作:
   串的逻辑结构和线性结构很相似,区别在于串约束了存储对象必须是字符,而线性表则没有限制,但是,串的基本操作和线性表有很大区别。
   
   串复制:将某个串复制给当前串
   判空:判断当前串是否为空,若当前串为空,则返回true,否则返回false
   串比较:判断当前串与指定串,若相等,返回0,若当前串>指定串返回1,否则返回-1
   求串长:返回当前串的字符个数
   串连接:将串S1和S2连接成一个新串,并赋值给串T
   求子串:返回当前串的第i个字符开始长达k个字符的子串
   子串定位:输出子串在当前串中首次出现的位置
   串替换:用子串x替换当前串中的子串y
   插入子串:将子串插入到当前串中的某个位置
   删除子串:将子串从当前串中的某个位置删除
   大写转小写:
   小写转大写:
   串压缩:去除当前串中的首部和尾部空格
       
   ~~~
4.1 串的顺序存储及实现
顺序串的三种实现方式:
1.用一个变量来表示串的长度
2.在串的尾部存储一个不会再串中出现的特殊字符作为串的
    
    终结符
3.用数组的0号单元存放串的长度,串值从1号下表开始存放

数据结构转换成json java 设置键的顺序_算法_50

/**
 * 顺序结构的串可以用字符数组来存储字符数组
 */
public class string {
    private int maxSize = 10; // 串字符数组的初始长度
    private char[] chars; // 存储元素的数组对象
    private int length = 0; // 保存串的当前长度
    // 构造一个空串
    public string() {
        this.chars = new char[maxSize];
        this.length = 0;
    }

    // 构造一个长度为n的串
    public string(int n) {
        this.maxSize =n;
        this.chars = new char[n];
        this.length = 0;
    }


    // 将串t赋值给当前串
    public void copy(string t) {
        if (this.maxSize < t.maxSize) {
//            若当前串无法容纳串t的内容,将扩容当前的容量
            this.maxSize = t.maxSize;
            this.chars = new char[this.maxSize];
        }
        this.length = 0;
        for (int i = 0; i < t.getLength(); i++) {
            this.chars[i] = t.chars[i];
            this.length++;
        }
    }

    // 判断当前串是否为空
    public boolean isEmpty() {
        return this.length == 0;
    }

    // 将当前串与串t进行比较
    public int compare(string t) {
//        相等返回0,当前串大于t返回1,当前串小于t返回-1
        int i = 0;
        while (this.chars[i] == t.chars[i] && i < this.length && i < t.length) {
            i++;
        }
        if (i == this.length && i == t.length) {
            return 0;
        } else if (i == t.length && i < this.length) {
            return 1;
        } else {
            return -1;
        }
    }

    // 求当前串的长度
    public int getLength() {
        return this.length;
    }

    // 清空当前串
    public void clear() {
        this.chars = null;
        this.length = 0;
    }

    // 将指定串拼接到当前串
    public void concat(string t) {
        if (this.maxSize < this.length + t.getLength()) {
//            扩容
            char[] a = new char[this.length];
            for (int i = 0; i < this.length; i++) {
                a[i] = this.chars[i];
            }

            this.maxSize = this.length + t.getLength();
            this.chars = new char[this.maxSize];

            for (int i = 0; i < this.length; i++) {
                this.chars[i] = a[i];
            }
        }
        for (int i = 0; i < t.getLength(); i++) {
            this.chars[this.length] = t.chars[i];
            this.length++;
        }
    }

    // 提取子串从主串的pos个位置开始获得len个字符
    public string subString(int pos, int len) {
        if (pos + len >= this.length) {
            return null;
        }
        string a = new string(len);
        for (int i = 0; i < len; i++) {
            a.chars[i] = this.chars[pos + i];
            a.length++;
        }
        return a;
    }

    // 提取子串从pos位置开始,知道当前串的最后
    public string subString(int pos) {
        if (pos  >= this.length) {
            return null;
        }
        string a = new string(this.length-pos);
        for (int i = 0; i < a.getLength(); i++) {
            a.chars[i] = this.chars[pos + i];
            a.length++;
        }
        return a;
    }

   // 有兴趣自己实现
    // 返回字符串t在当前字符串中的首次出现的位置
    public int index(string t) {
        return 0;
    }

    // 返回字符串t在当前字符串中的最后出现的位置
    public int lastIndex(string t) {
        return 0;
    }

    // 在当前串中用串v替换所有与串t相等的串
    public int replace(string t, string v) {
        return 0;
    }

    // 将串t插入到当前串的第pos个位置
    public boolean insert(string t, int pos) {
        return false;
    }

    // 删除当前串中从第pos个位置上的连续len个字符
    public boolean delete(int pos, int n) {
        return false;
    }

    // 在当前串中删除所有与串t相等的串
    public int remove(string t) {
        return 0;
    }

    // 转大写
    public void toUpperCase() {

    }

    // 转小写
    public void toLowerCase() {

    }
}

数据结构转换成json java 设置键的顺序_算法_51

模式匹配:模式匹配:在当前串中查找子串的过程为模式匹配,其中该子串称为模式串。
  // 返回字符串t在当前字符串中的首次出现的位置
    public int index(string t) {
        if (this.length < t.length) {
            return -1;
        }
        int a = -1;
        for (int i = 0; i < this.length; i++) {
            int j = 0;
            for (j = 0; j < t.getLength() && this.chars[i + j] == t.chars[j]; j++) {

            }
            if (j == t.getLength()) {
                a = i;
                break;
            }
        }
        return a;
    }

数据结构转换成json java 设置键的顺序_数据结构_52

数据结构转换成json java 设置键的顺序_数据_53