数据结构——(2)、线性表

一、线性表相关概念

1、定义

线性表是具有相同特性数据元素的有限序列。该序列中所含元素的个数叫线性表的长度,用n(n>=0)表示。注意,n可以等于零,表示一个空表。

线性表有序序列,数据元素具有相同的特性,线性表可以有无性。

2、逻辑特性

其他元素只有一个直接前驱,也直接后继。

3、结构特点

存在唯一一个被称为“第一个”的数据元素。

  • 存在唯一一个被称为“最后一个”的数据元素。

  • 除“第一个”之外,集合中的每个元素均只有一个前驱。

  • 除“最后一个”之外,集合中的每个元素均只有一个后继。

  • 数据元素之间的关系是线性的。

4、线性表的顺序表示

用一组地址连续的存储单元依次存储线性表的数据元素。每一个数据元素的储存 位置都和线性表的起始位置相差一个和数据元素在线性表中的位序成正比的常数。由此,只要确定了存储线性表的起始位置,线性表中任一数据元素都可随机存取,所以线性表的顺序存储结构是一种随机存取的存储结构。

二、存储结构

1、线性表的存储结构

(1)、顺序表

定义:顺序表把线性表的所有元素按照其逻辑顺序,依次存储到从指定的存储位置开始的一块连续的存储结构空间中。

特性:

  1. 随机访问特性。

  2. 占用连续的存储空间。

(2)、链表

定义:在存储链表中,每个节点不仅包含所存元素的信息,还包含元素之间逻辑关系的信息。可以通过前驱结点中的地址信息找到后继结点的位置。

特性:

  1. 不支持随机访问的特性。

  2. 结点的存储空间利用率较顺序表稍微低一些。

  3. 不需要一次性划分所有结点所需空间给链表。

  4. 链表支持存储空间的动态分配。

顺序表和链表区别:顺序表在做插入操作的时候需要移动多个元素,链表进行插入操作无需移动元素。

2、顺序表上基本运算的实现

(1)、初始化顺序表

初始化顺序表就是创建一个用于存放线性表的空的顺序表,创建过程如下:

  1. 初始化maxsie为实际值

  2. 为数组申请可以存储 maxsize 个数据元素的存储空间,数据元素的类型由实际应用而定

  3. 初始化 size 为 0

(2)、插入元素 boolean add(int index, E item)

插入数据元素是指假设线性表中己有 size(0≤size≤maxsize—1)个数据元素,在索引位置 i(O≤index≤size)处插入一个新的数据元素。创建过程如下:

a、若没有指定插入位置,则将数据元素插入到顺序表最末的位置;指定插入位置index。若插入索引位置 index<0 或 index>size,则无法插入。

 b、将索引位置为 index~size-1 存储位置上的元素(共 size-index 个数据元素)依次后移后,将新的数据元素置于 index 位置上。

c、顺序表长度 size 加 1。

(3)、删除操作 remove(int index)

假设顺序表中己有 size(1≤size≤maxsize)个数据元素,删除指定索引位置的数据元素。具体算法如下:

a、如果列表为空,或不符合 0≤index≤size一1,则提示没有要删除的元素。

b、将第index+1到第size-1索引位置上数据元素(共size-1-index个数据元素)依次前移。

c、清除最后一个数据元素的值,使顺序表的表长度size-1

3、链表的五种形式

(1)、单链表

带头结点与不带头结点的区别:

  • 带头结点的单链表中头指针head指向头结点,头结点的值域不含任何信息,从头结点的后继结点开始存储信息。对于带头结点的单链表,它的头指针head始终不等于NULL,head->next等于NULL的时候链表为空。

  • 不带头结点的单链表中的头指针head直接指向开始结点,即图2-2中的结点A1,当head等于NULL的时候链表为空。

总之,两者最明显的区别是,带头结点的单链表有一个结点不存储信息,只是作为标志,而不带头NULL的时候链表为空。

(2)、双链表

双链表就是在单链表结点上增添了一个指针域,指向当前结点的前驱。这样就可以方便地由其后继来找到其前驱,从而实现输出终端结点到开始结点的数据序列。同样,双链表也分为带头结点的双链表和不带头结点的双链表,情况类似于单链表。

双链表结构具有对称性,设 p 指向双向链表中的某一结点,则其对称性可用下式描述:

(p->prior)->next=p=(p->next)->prior

带头结点的双链表当head->next为NULL时链表为空,   不带头结点的双链表当head为NULL时链表为空。

双链表的结点结构:

双向链表为空时;当链表为空时,要将首节点的next指向尾节点,尾节点的prior指向首节点。

双向链表不为空时;每一个节点(首位节点除外)的两个指针域都分别指向其前驱和后继。

双向链表存储结构:

/*线性表的双向链表存储结构*/
typedef struct DulNode{
  DataType data;
  struct DulNode *prior; 
  //指向前驱的指针域  
  struct DulNode *next; 
  //指向后继的指针域
}DulNode, *DuLinkList;

(3)、循环单链表

循环单链表可以实现从任一结点出发访问链表的任何结点,而单链表从任一结点出发后只能访问这个结点本身及其后边的所有结点。

循环单链表和单链表的区别在于,表中最后一个结点的指针不是NULL,而改为指向头结点,从而整个链表形成一个环。

带头结点的循环单链表,链表空:head=head->next;不带头结点,链表空:head=NULL

(4)、循环双链表

循环双链表即终端结点的next指针指向链表中的第一个结点,将链表中第一个结点的prior指针指向终端结点。

带头结点的循环双链表head->next和 head->prior两个指针都等于head时链表为空,不带头结点的循环双链表当head等于NULL时链表为空

双向循环链表的插入和删除

p 之后插入 s

p 之前插入 s

删除 p 之后继 s

删除 p

s->next = p->next; 

p->next = s; 

s->prior = p; 

s->next->prior = s;

s->prior = p->prior; 

p->prior = s; 

s->next = p; 

s->prior->next = s;

s = p->next; 

p->next = s->next;

 p->next->prior = p;

p->prior->next = p->next; 

p->next->prior = p->prior;

(5)、静态链表

静态链表借助一维数组来表示。静态链表来自于一个结构体数组

4、线性表的存储结构

顺序存储结构用一组地址连续的存储单元依次存储线性表的数据元素。把线性表的数据元素按逻辑顺序依次存放在一组地址连续的存储单元里。用这种方法存储的线性表简称顺序表。

    在顺序表的存储结构中,    一般来说,线性表的第i个元素ai的存储位置为:LOC(ai)=LOC(a1)+(n-1) 。假设每个数据元素在存储器中占用k个存储单元,索引号为0的数据元素的内存地址为 Loc(ay),    其中LOC(a1)是线性表的第一个元素ai的存储位置,通常称为基地址,则数据元素 ai的索引号为i-1,其内存地址为:

LOC(ai)=LOC(ai)+(i-1)×k

顺序存储结构缺点:

  1. 再进行插入或者删除操作时,需要移动大量元素

  2. 再给长度变化较大的线性表预先分配空间时,必须按最大空间分配,使存储结构不能得到充分利用

  3. 表的容量难以扩充

5、线性表的抽象数据类型

public interface ILinarList<E> {
    boolean add(E item);                 //添加元素
    boolean add(int index, E item);      //插入元素
    E remove(int index);                 //删除元素
    int indexOf(E item);                 //定位元素
    E get(int index);                    //取表元素
    int size();                          //求线性表长度
    void clear();                        //清空线性表
    boolean isEmpty();                   //判断线性表是否为空
}

6、单链表的基本运算

(1)、初始化单链表

初始化单链表就是创建一个空的单链表,步骤如下:

  1. 声明一个为单链表结点类型的 start 变量,用来指向单链表的第一个结点。

  2. 在单链表的构造函数中将 start 变量的值赋为 null。

(2)、插入元素 add(int index, Eitem)

在单链表中添加一个新的结点通常分为下面的三种情况:

a、在单链表开头插入一个新的结点

 ①、为新结点分配内存并为数据字段分配值

②、使新结点的next字段指向链表中的第一个结点

③、使start指向新结点

b、在链接表的两个结点之间插入结点

①、为新结点分配内存并为数据字段分配值

②、根据索引号 index 确定要在哪个结点前插人新结点。将它们标记为前一个结点revious 和当前结点 current。找到前一个和当前结点,并执行以下步骤:

  • previous 指向 null

  • current 指向第一个结点

  • 如果新结点的索引号 index 大于当前结点的索引号 i,重复步骤 d 和步骤 e

  • previous 指向 current

  • current 指向序列中的下一个结点。

③、新结点的next字段指向当前结点

④、前一个结点的next字段指向新结点

c、在单链表末尾插人一个新的结点

在单链表的末尾插人结点是在链接表的两个结点之间插人结点的特殊情况,当 current为 null、previous 指向最后一个结点时,即可将新结点插人到链接表的末尾。如果在某些情况下,非常明确就是要将结点插入到链接表的末尾,可执行下面的算法步骤:

①、为新结点分配内存并为数据字段分配值

②、找到链表中的最后一个结点,将它标记为current

(3)、删除元素

从单链表中删除指定的结点,首先要判断是否为空,如果不为空,要搜索指定的结点,如果找到指定的结点,则将其删除并返回该结点,否则返回null,找到删除的结点后,在单链表中删除指定的结点,通常分三种情况:

a、从单链表的开头删除结点

①、将链表中的第一个节点记为当前结点

②、使用start指向单链表中的下一个结点

③、释放标记为当前结点的内存

b、删除单链表中两个结点之间的结点

①、定位要删除的结点,步骤如下:

  • 将前一个结点previous设置为start

  • 将当前结点current设置为start

  • 比较当前结点current和要删除结点的索引号index,直到相等或当前结点变成为null为止,否则重复d和e

  • 前一个结点previous指向当前结点current

  • current指向链表中的下一个结点

  • ②、当ai的索引号为index时,使当前结点current的前一个结点指向当前结点current的下一个结点

    ③、释放标记为当前结点的结点内存,current设为null

    c、删除单链表末尾的结点

    在上述删除单链表两个结点之间的结点的算法中,如果搜索操作后,当前结点 current 指向单链表中最后一个结点,则说明要删除的结点是链表中最后一个结点。该算法也能删除单链表末尾的结点。因此无须专门创建删除单链表末尾结点的算法。

    (4)、取表元素 get(int index)和定位元素 indexOf(E item)

    取表元素和定位元素是指根据给定的索引值或结点值,搜索对应该索引值或结点值的结点。具体过程如下:

    ①、将单链表的起始结点标记为当前结点 current。

    ②、如果单链表不为空链表,比较要查找结点的索引号 index 或值是否与 current 所指向结点的索引号或值相等,如果不等 current 指向下一个结点,找到该结点时,返回 current。

    ③、当 current 为 null 时,表示没有找到指定的结点。

    7、顺序表java实现

//定义接口操作
public interface ILinarList<E> {
    boolean add(E item);                 //添加元素
    boolean add(int index, E item);      //插入元素
    E remove(int index);                 //删除元素
    int indexOf(E item);                 //定位元素
    E get(int index);                    //取表元素
    int size();                          //求线性表长度
    void clear();                        //清空线性表
    boolean isEmpty();                   //判断线性表是否为空
}


import java.lang.reflect.Array;
public class SeqList<E> implements ILinarList<E> {
    private int maxsize; // 顺序表的最大容量
    private E[] data; // 数组,用于存储顺序表中的数据元素
    private int size; // 顺序表的实际长度
    // 初始化线性表
    @SuppressWarnings("unchecked")
    public SeqList(Class<E> type, int maxsize) {
        this.maxsize = maxsize;
        data = (E[]) Array.newInstance(type, maxsize);  //Array.newInstance()创建动态数组
        size = 0;
    }
    // 添加元素,将元素添加在顺序表的末尾
    public boolean add(E item) {
        if (!isFull()) {
            data[size++] = item;
            return true;
        } else
            return false;
    }
    // 插入元素,将元素添加在顺序表指定的位置
    public boolean add(int index, E item) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        if (!isFull()) {
            for (int j = size - 1; j >= index; j--) {
                data[j + 1] = data[j];
            }
            data[index] = item;
            size++;
            return true;
        } else
            return false;
    }
    // 删除元素,删除顺序表的第i个数据元素
    public E remove(int index) {
        rangeCheck(index);
        if (!isEmpty()) {
            E oldValue = data[index];
            for (int j = index; j < size-1; j++) {
                data[j] = data[j+1];
            }
            data[--size] = null;// 清除最后一个元素
            return oldValue;
        } else
            return null;
    }
    // 定位元素,返回对象item在顺序表中首先出现的索引位置,不存在item,则返回-1
    public int indexOf(E item) {
        if (item == null) {
            for (int i = 0; i < size; i++)
                if (data[i] == null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (item.equals(data[i]))
                    return i;
        }
        return -1;
    }
    // 取表元素,返回顺序表中指定索引位置index处的数据元素
    public E get(int index) {
        rangeCheck(index);
        return data[index];
    }
    // 求顺序表长度
    public int size() {
        return size;
    }
    // 清空顺序表
    public void clear() {
        for (int i = 0; i < size; i++)
            data[i] = null;
        size = 0;
    }
    // 判断顺序表是否为空
    public boolean isEmpty() {
        return size == 0;
    }
    // 判断给定的索引号是否在指定的范围,如果不在,抛出索引越界异常
    private void rangeCheck(int index) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
                    + size);
    }
    // 判断顺序表是否为满
    public boolean isFull() {
        if (size == maxsize) {
            return true;
        } else {
            return false;
        }
    }
}


//主方法
import java.util.Scanner;
public class Test {
    public static void main(String[] args) {
        ILinarList<Integer> list = new SeqList<Integer>(Integer.class, 50);
        int[] data = {23, 56, 78, 95, 62};
        Scanner sc = new Scanner(System.in);
        System.out.println("1、添加元素");
        System.out.println("2、插入元素");
        System.out.println("3、删除元素");
        System.out.println("4、定位元素");
        System.out.println("5、取表元素");
        System.out.println("6、显示线性表");
        System.out.println("0、退出");
        char ch;
        do {
            System.out.println("请输入操作选项");
            ch = sc.next().charAt(0);
            switch (ch) {
                case '1':
                    for (int i = 0; i < data.length; i++) {
                        list.add(data[i]);
                    }
                    System.out.println("添加操作成功");
                    break;
                case '2':
                    System.out.println("请输入要插入的位置:");
                    int loc = sc.nextInt();
                    System.out.println("请输入要插入该位置的值:");
                    int num = sc.nextInt();
                    list.add(loc - 1, num);
                    System.out.println("插入操作成功");
                    break;
                case '3':
                    System.out.println("请输入要删除元素的位置");
                    loc = sc.nextInt();
                    list.remove(loc - 1);
                    System.out.println("删除操作成功");
                    break;
                case '4':
                    System.out.println("请输入要查找的元素");
                    num = sc.nextInt();
                    System.out.println(num + "在表中的位置为:" + (list.indexOf(num) + 1));
                    break;
                case '5':
                    System.out.println("请输入要查找元素的位置:");
                    loc = sc.nextInt();
                    System.out.println(loc + "位置上的元素为:" + list.get(loc - 1));
                    break;
                case '6':
                    System.out.println("线性表中的元素有:");
                    for (int i = 0; i < list.size(); i++) {
                        System.out.println(list.get(i) + " ");
                    }
                    System.out.println();
                    break;
            }
        } while (ch != '0');
        sc.close();
    }
}

8、线性表c语言实现

#构造空线性表
#include <stdio.h>
#include <malloc.h>
#define LIST_INIT_SIZE 100    //线性表存储空间的初始分配量
#define LISTINCREMENT 10      //线性表存储空间的分配增量
typedef struct {
        ElemType *elem;               //存储空间基址
        int length;            //当前长度
        int listsize;  //当前分配的存储容量(以sizeof(ElemType)为单位)
}SqList;
Status InitList_Sq(SqList &L) {
        //构造空链表
        L.elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType))
               if (! L.elem)exit(OVERFLOW);          //存储分配失败
               L.length = 0;          //空表长度为0
               L.listsize = LIST_INIT_SIZE;          //初始存储容量
               return OK;
        } //InitList_Sq
}


#线性表创建
#include <stdio.h>
#include <malloc.h>
typedef struct student        //自定义链表结点
{
    int score;        //结点数据域
    char name[20];        
    struct student* next;    //结点指针域
}ST, *STU;        //自定义链表节点数据类型ST,指针数据名STU
/*
头指针
*/
STU creatlink(int n){        //定义STU类型creatlink函数,参数为n
    int i;        //申明常量
    STU p,q,head;        //申明STU类型的结点
    if (n <= 0){ return(NULL); }    //判断输入的n值
    head = (STU)malloc(sizeof(ST));        //申请在堆内存中开辟一块STU类型数据ST并赋值给head结点
    printf("input datas:\n");    
    scanf_s("%s%d",p->name,&p->score);    //获取数据,字符内容不用传地址符
    p=head;        //p指针调到head结点上
    for (i = 1; i < n; i++) {    //根据学生数n循环输入链表数据
        q = (STU)malloc(sizeof(ST));    //申请在堆内存中开辟一块STU类型数据ST并赋值给head结点
        scanf_s("%s%d", q->name, &q->score);    //获取数据,字符内容不用传地址符
        p->next = q;    //指针p的下一结点指向q
        p = q;    //指针p跳转到q结点
    }
    p->next=NULL;        //指针p的下一个结点为空,即指向尾结点
    return(head);    //返回指针
    return 0;    
}
/*
输出函数
*/
void list(STU head) {        //定义无返回值的list函数,传入STU类型head变量
    STU p = head;        //STU类型指针p指向head结点
    while (p != NULL){    //判断p不指向尾结点
        printf("%s\t%d\n", p->name, p->score);    //输出
        p = p->next;    //指针p顺序后移一个结点
    }
    return 0;    
}
void main() {
    STU h;    //STU类型指针h
    int n;
    printf("input number of node:");
    scanf_s("%d\n", &n);    
    h = creatlink(h);    //调用建立单链表的函数
    list(h);    //调用输出函数
    return 0;
}


#线性表元素插入
#include <stdio.h>
#include <malloc.h>
typedef struct student        //自定义链表结点
{
        int score;             //结点数据域
        char name[20];         
        struct student* next;  //结点指针域
}ST, *STU;             //自定义链表节点数据类型ST,指针数据名STU
/*
头指针
*/
STU creatlink(int n){         //定义STU类型creatlink函数,参数为n
        int i;         //申明常量
        STU p,q,head;          //申明STU类型的结点
        if (n <= 0){ return(NULL); }  //判断输入的n值
        head = (STU)malloc(sizeof(ST));              //申请在堆内存中开辟一块STU类型数据ST并赋值给head结点
        printf("input datas:\n");     
        scanf_s("%ps%pd%",p->name,&p->score); //获取数据,字符内容不用传地址符
        p=head;        //p指针调到head结点上
        for (i = 1; i < n; i++) {     //根据学生数n循环输入链表数据
               q = (STU)malloc(sizeof(ST));  //申请在堆内存中开辟一块STU类型数据ST并赋值给head结点
               scanf_s("%s%d", q->name, &q->score);  //获取数据,字符内容不用传地址符
               p->next = q;   //指针p的下一结点指向q
               p = q;  //指针p跳转到q结点
        }
        p->next=NULL;          //指针p的下一个结点为空,即指向尾结点
        return(head);  //返回指针
        return 0;      
}
/*
插入函数
*/
STU increasenode2(STU head,int i){
        STU q, p, s;
        int j = 0;
        if (i < 0) { return NULL; }
        s = (STU)malloc(sizeof(ST));
        printf("input new node datas:");
        scanf("%s%d",s->name,s->score);
        if (i == 0) {
               s->next = head;
               head = s;
               return(head);
        }
        q = head;
        while (j < i && q != NULL) {
               j++;
               p = q;
               q = p->next;
        }
        if (j < i) { return NULL; }
        p->next = s;
        s->next = q;
        return (head);
}
/*
输出函数
*/
        void list(STU head) {         //定义无返回值的list函数,传入STU类型head变量
               STU p = head;          //STU类型指针p指向head结点
               while (p != NULL){     //判断p不指向尾结点
                       printf("%s\t%d\n", p->name, p->score);       //输出
                       p = p->next;   //指针p顺序后移一个结点
               }   
        return 0;  
        }
void main() {
        STU h;  //STU类型指针h
        int n,i;
        printf("input number of node:");
        scanf_s("%d\n", &n);   
        h = creatlink(n);      //调用建立单链表的函数
        list(h);       //调用输出函数
        return 0;
}


#线性表删除元素
#include <stdio.h>
#include <malloc.h>
typedef struct student        //自定义链表结点
{
        int score;             //结点数据域
        char name[20];         
        struct student* next;  //结点指针域
}ST, *STU;             //自定义链表节点数据类型ST,指针数据名STU
/*
头指针
*/
STU creatlink(int n){         //定义STU类型creatlink函数,参数为n
        int i;         //申明常量
        STU p,q,head;          //申明STU类型的结点
        if (n <= 0){ return(NULL); }  //判断输入的n值
        head = (STU)malloc(sizeof(ST));              //申请在堆内存中开辟一块STU类型数据ST并赋值给head结点
        printf("input datas:\n");     
        scanf_s("%ps%pd%",p->name,&p->score); //获取数据,字符内容不用传地址符
        p=head;        //p指针调到head结点上
        for (i = 1; i < n; i++) {     //根据学生数n循环输入链表数据
               q = (STU)malloc(sizeof(ST));  //申请在堆内存中开辟一块STU类型数据ST并赋值给head结点
               scanf_s("%s%d", q->name, &q->score);  //获取数据,字符内容不用传地址符
               p->next = q;   //指针p的下一结点指向q
               p = q;  //指针p跳转到q结点
        }
        p->next=NULL;          //指针p的下一个结点为空,即指向尾结点
        return(head);  //返回指针
}
/*
输出函数
*/
void list(STU head) {         //定义无返回值的list函数,传入STU类型head变量
        STU p = head;          //STU类型指针p指向head结点
        while (p != NULL) {    //判断p不指向尾结点
               printf("%s\t%d\n", p->name, p->score);       //输出
               p = p->next;   //指针p顺序后移一个结点
        }
}
/*
删除函数
*/
STU deletenode2(STU head, int i) {
        STU p, s;
        int j;
        if (i < 1)
               return NULL;
        if (i == 0) {
               if (head != NULL) {
                       s = head;
                       head = s->next;
                       free(s);
               }
               s = head->next;
               p = head;
               j = 2;
               while (j < i && s != NULL) {
                       j++;
                       p = s;
                       s = s->next;
               }
               if (j < i) { return NULL; }
               p->next = s->next;
               return (head);
        }
}
void main(){
        STU h;  //STU类型指针h
        int n,i;
        printf("input number of node:");
        scanf_s("%d\n", &n);   
        h = creatlink(n);      //调用建立单链表的函数
        list(h);       //调用输出函数
        printf("which node do you  want to delete:");
        scanf("%d", &i);
        h = deletenode2(h,i);
        list(h);
        return 0;
}


#线性表元素合并
#include <stdio.h>
#include <malloc.h>
/*
已知线性表La和Lb中的数据元素按值非递减排列
归并La和Lb得到新的线性表Lc,Lc的数据元素也按值非递减排列
*/
void main(List La,List Lb, List &Lc) {
        InitList(Lc);
        i = j = 0;
        k = 0;
        La_Len = ListLength(La);
        Lb_Len = ListLength(Lb);
        while ((i <= La_Len) && (j <= Lb_Len))
               GetElem(La, i, ai);
               GetElem(Lb, j, bj);
               if (ai <= bj)
               {
                       ListInsert(Lc, ++k, ai);
                       ++i;
               }
               else {
                       ListInsert(Lc, ++k, bj);
                       ++j;
               }
               while (i<=La_Len) {
                       GetElem(La, i, ai);
                       ListInsert(Lc, ++k, ai);
               }
               while (j <= Lb_Len) {
                       GetElem(Lb, j++, bj);
                       ListInsert(Lc, ++k, bj);
             }
}

9、单链表Java实现

//定义接口
public interface ILinarList<E> {
    boolean add(E item); //添加元素
    boolean add(int index, E item);//插入元素
    E remove(int index); //删除元素
    int indexOf(E item); //定位元素
    E get(int index); //取表元素
    int size(); //求线性表长度
    void clear();//清空线性表
    boolean isEmpty(); //判断线性表是否为空
}


public class SLinkList<E> implements ILinarList<E>{
    private Node<E> start;      //声明一个为单链表结点类型的start变量,用来指向单链表的第一个结点
    int size;       //单链表的长度
    private static class Node<E>{
        E item;
        Node<E> next;
        Node(E element,Node<E> next){
            this.item = element;
            this.next = next;
        }
    }
    //初始化线性表
    public SLinkList(){
        start = null;
    }
    //添加元素,将元素添加在单链表的末尾
    public boolean add(E item){
        if(start == null){
            start = new Node<E>(item,null);
        }else{
            Node<E> current = start;
            while(current.next!=null) {
                current = current.next;
            }
            current.next = new Node<E>(item,null);
        }
        size++;
        return true;
    }
    //在单链表前的第index个索引位置前插入一个数据元素
    public boolean add(int index,E item){
        Node<E>current;
        Node<E>previous;
        if(index<0 || index>size){
            return false;
        }
        Node<E>newnode = new Node<E>(item,null);
        //在空链表或第一个元素前插入第一个元素
        if(index == 0){
            newnode.next = start;
            start = newnode;
            size++;
        }else{
            //单链表的两个元素之间插入一个元素
            current = start;
            previous = null;
            int j = 0;
            while(current != null && j < index){
                previous = current;
                current = current.next;
                j++;
            }
            if(j == index){
                previous.next = newnode;
                newnode.next = current;
                size++;
            }
        }
        return true;
    }
    //删除单链表中的索引位置为index的数据元素
    public E remove(int index){
        E oldValue = null;
        if(isEmpty() || index<0 || index>size-1){
            oldValue = null;
        }
        Node<E> current = start;
        if(index == 0){
            oldValue = current.item;
            start = current.next;
            size--;
        }else{
            Node<E> previous = null;
            int j = 1;
            while(current.next != null && j<index){
                previous = current;
                current = current.next;
                j++;
            }
            previous.next = current.next;
            oldValue = current.item;
            current = null;
            size--;
        }
        return oldValue;
    }
    //在单链表中查找数据元素item数据位置
    public int indexOf(E item){
        int index = 0;
        if(item == null){
            for(Node<E> x =start;x!= null;x=x.next){
                if(x.item == null)
                    return index;
                index++;
            }
        }else{
            for(Node<E> x = start;x!= null;x=x.next){
                if(item.equals(x.item))
                    return index;
                index++;
            }
        }
        return -1;
    }
    //获得单链表的第index索引位置的数据元素
    public E get(int index){
        E item = null;
        if(isEmpty() || index<0 || index>size-1){
            item = null;
        }
        Node<E> current = start;
        int j = 0;
        while(current.next != null && j<index){
            current = current.next;
            j++;
        }
        if(j == index){
            item = current.item;
        }
        return item;
    }
    //求单链表长度
    public int size(){
        return size;
    }
    //清空单链表
    public void clear(){
        for(Node<E>x = start;x!=null;){
            Node<E>next = x.next;
            x.item = null;
            x.next = null;
            x = null;
        }
        start = null;
        size = 0;
    }
    //判断单链表是否为空
    @Override
    public boolean isEmpty() {
        return size == 0;
    }
}


public class Test {
    public static void main(String[] args) {
        ILinarList<Integer> list = new SLinkList<Integer>();
        int[] data = {45,89,26,15,59,48,75};
        Scanner sc = new Scanner(System.in);
        System.out.println("1、添加元素");
        System.out.println("2、插入元素");
        System.out.println("3、删除元素");
        System.out.println("4、定位元素");
        System.out.println("5、取表元素");
        System.out.println("6、显示单链表");
        System.out.println("0、退出");
        char ch;
        do {
            System.out.println("请输入操作选项");
            ch = sc.next().charAt(0);
            switch (ch) {
                case '1':
                    for (int i = 0; i < data.length; i++) {
                        list.add(data[i]);
                    }
                    System.out.println("添加操作成功");
                    break;
                case '2':
                    System.out.println("请输入要插入的位置:");
                    int loc = sc.nextInt();
                    System.out.println("请输入要插入该位置的值:");
                    int num = sc.nextInt();
                    list.add(loc - 1, num);
                    System.out.println("插入操作成功");
                    break;
                case '3':
                    System.out.println("请输入要删除元素的位置");
                    loc = sc.nextInt();
                    list.remove(loc - 1);
                    System.out.println("删除操作成功");
                    break;
                case '4':
                    System.out.println("请输入要查找的元素");
                    num = sc.nextInt();
                    System.out.println(num + "在表中的位置为:" + (list.indexOf(num) + 1));
                    break;
                case '5':
                    System.out.println("请输入要查找元素的位置:");
                    loc = sc.nextInt();
                    System.out.println(loc + "位置上的元素为:" + list.get(loc - 1));
                    break;
                case '6':
                    System.out.println("单链表中的元素有:");
                    for (int i = 0; i < list.size(); i++) {
                        System.out.println(list.get(i) + " ");
                    }
                    System.out.println();
                    break;
            }
        } while (ch != '0');
        sc.close();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41819893/article/details/121323727
今日推荐