一、线性表:n个相同类型数据的有限序列(n>=0)。
常用操作:增(尾部)、删、插、查、遍历、求表长、判断是否为空
操作特点:可以在任意位置插入或删除一个元素。
二、顺序表:用顺序结构实现的线性表。
Java类库中的顺序表:ArrayList
//StudIn类:定义顺序表中的数据元素
public class StudIn {
private String name;
private int id;
private double score;
public StudIn(String name,int id,double score){
this.name=name;
this.id=id;
this.score=score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "StudIn [姓名=" + name + ", 学号=" + id + ", 分数=" + score + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
long temp;
temp = Double.doubleToLongBits(score);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
StudIn other = (StudIn) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Double.doubleToLongBits(score) != Double.doubleToLongBits(other.score))
return false;
return true;
}
}
//StudOPeration接口:定义顺序表的数据操作
public interface StudOPeration {
void add(StudIn node);//在尾部添加一个学生记录
void listAll();//遍历学生记录
void search(int index);//查询某个位置上学生的信息并输出
int getCounts();//获取学生记录个数
void delete(int index);//根据记录序号删除学生记录
void delete(String name);//根据学生姓名删除学生信息
void search(String name);//根据学生姓名查找学生信息
}
//ArrStudentl类:是一个顺序表,用来实现StudOPeration接口
public class ArrStudent implements StudOPeration{
// StudIn[]stud=new StudIn[5];
StudIn stud[];
public ArrStudent(int size) { //指定顺序表的容量
// TODO Auto-generated constructor stub
stud=new StudIn[size];
}
int cout=0;//记录计数器,记当前顺序表中 的记录个数
@Override
public void add(StudIn node) { //添加纪录
// TODO Auto-generated method stub
int i=cout;
stud[i]=node;
cout++;
if(cout==stud.length){
System.out.println("存储空间已满");
}
}
@Override
public void listAll() { //显示所有记录
// TODO Auto-generated method stub
try{for(int i=0;i<cout;i++){
System.out.println(stud[i].getName()+"\t"+stud[i].getId()+"\t"+stud[i].getScore());
}}catch(NullPointerException e){
e.printStackTrace();
}
}
@Override
public void search(int index) { //查询记录
// TODO Auto-generated method stub
if(index<=stud.length&&index>0){
System.out.println("您查找的信息为:"+stud[index-1]);
}else{
System.out.println("输入序号无效");
}
}
@Override
public int getCounts() { //获取学生记录个数
// TODO Auto-generated method stub
return cout;
}
@Override
public void delete(int index) {
// TODO Auto-generated method stub
cout=cout-1;
stud=ArrStudent.removeElementByCopy(stud, index);
System.out.println("删除成功!");
}
public static StudIn[] removeElementByCopy(StudIn[] array, int position) {
if (position < 0 || position > array.length) {
throw new IndexOutOfBoundsException("the position is out of the array indices");
}
StudIn[] newArray = new StudIn[array.length - 1];
int index = position - 1;
System.arraycopy(array, 0, newArray, 0, index);
if (index < array.length - 1) {
System.arraycopy(array, index + 1, newArray, index, array.length - index - 1);
}
return newArray;
}
@Override
public void delete(String name) {
// TODO Auto-generated method stub
int flag=-1;
for(int i=0;i<cout;i++){
if(stud[i].getName().equals(name)){
cout=cout-1;
stud=ArrStudent.removeElementByCopy(stud, i+1);
System.out.println("删除成功!");
flag=1;
}
if(flag==-1){
System.out.println("没找到该学生信息!");
}
}
}
@Override
public void search(String name) {
// TODO Auto-generated method stub
int flag=-1;
for(int i=0;i<cout;i++){
if(stud[i].getName().equals(name)){
System.out.println(stud[i].toString());
flag=1;
break;
}
if(flag==-1){
System.out.println("没有找到该学生信息");
}
}
}
}
import java.io.*;
public class ArrStudentUser {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrStudent stud=new ArrStudent(10);
// ArrStudent stud=new ArrStudent();
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
while(true){
System.out.println("********学生信息管理系统********");
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("7 输入学生姓名删除学生记录");
System.out.println("0 退出\n");
System.out.print("输入你的选择:");
try {
int choice=Integer.parseInt(br.readLine());
switch (choice) {
case 0:
System.exit(0);
break;
case 1:
System.out.println("输入学生姓名:");
String Sname=br.readLine().toString();
System.out.println("输入学生学号:");
int Sid=Integer.parseInt(br.readLine());
System.out.println("输入学生成绩:");
int Sscore=Integer.parseInt(br.readLine());
StudIn sd=new StudIn(Sname, Sid, Sscore);
stud.add(sd);
System.out.println("信息添加完毕!");
break;
case 2:
System.out.println("姓名:\t学号:\t成绩:");
try{stud.listAll();
}catch(NullPointerException e){
e.printStackTrace();
}
break;
case 3:
System.out.println("输入学生的位置序号:");
int index=Integer.parseInt(br.readLine());
stud.search(index);
break;
case 4:
System.out.println("输入记录序号:");
int index1=Integer.parseInt(br.readLine());
stud.delete(index1);
break;
case 5:
System.out.println("学生记录个数为:"+stud.getCounts());
break;
case 6:
System.out.println("输入学生姓名:");
String Sname1=br.readLine();
stud.search(Sname1);
break;
case 7:
System.out.println("输入学生姓名:");
String Dname=br.readLine();
stud.delete(Dname);
break;
default:
break;
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// finally {
// if(null!=br){
// try {
// br.close();
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
// }
}
}
}
三、链表:使用链式存储结构存储数据的线性表称为链表
分为:单链表、双链表、循环单链表、双向循环链表。
Java类库中链表:LinkedList类是一个双向链表结构,可用来作为单链表或双向链表使用
带头结点的循环单链表
CircList.h
//
// Created by zhangzhiqiang on 2020/7/5.
//
#ifndef DATASTRUCTURE_CIRCLIST_H
#define DATASTRUCTURE_CIRCLIST_H
#include <iostream>
using namespace std;
class LinkNode{//单链表结点
public:
LinkNode *link;//指针域
int data;//数据域
};
//带头结点的循环单链表
class CircList{
private:
LinkNode *first,*last;//first指向头结点,last指向尾结点
public:
CircList();//构造函数
bool Insert(int &x);//将新元素x插入
bool Remove(int i,int &x);//删除第i个位置的结点(i从1开始),将被删结点值通过引用类型x返回
void Print();
};
#endif //DATASTRUCTURE_CIRCLIST_H
CircList.cpp
//
// Created by zhang zhiqiang on 2021/9/11.
//
#include "CircList.h"
//构造函数,初始化附加头结点的循环单链表
CircList::CircList() {
LinkNode *headNode=new LinkNode;//分配一个头结点
headNode->link=headNode;//link域存放的是头结点的地址
first=headNode;//头指针指向头结点
last=headNode;//尾指针指向头结点
}
//将新元素x插入到循环链表
bool CircList::Insert(int &x) {
LinkNode *newNode=new LinkNode;//为新插入元素构建结点
newNode->data=x;//数据域存放元素值
//尾插法(新插入元素作为表尾)
newNode->link=first;//新插入元素的结点作为尾结点,指向头结点
last->link=newNode;//插入在最后一个结点后面
last=newNode;//尾指针指向尾结点
return true;
}
//删除第i个位置的结点(i从1开始),将被删结点值通过引用类型x返回
bool CircList::Remove(int i, int &x) {
LinkNode *current;//被删除结点的前一个结点
LinkNode *del;//被删除结点
current=first;//先将结点指向头结点,然后遍历寻找第i个位置的前一个结点
for (int j = 0; j < i-1; ++j) {
current=current->link;
}
del=current->link;//找到删除结点
x=del->data;//保存删除结点的元素值
if(del==last){//删除位置为表尾结点
current->link=first;//则current变成表尾,让其指向头结点
last=current;//修改表尾指针
}else{
current->link=del->link;//重新拉链,表尾指针不变
}
delete del;//删除结点
return true;
}
//打印链表元素
void CircList::Print() {
LinkNode *current=first->link;
do{
cout<<current->data<<",";
current=current->link;
}while (current->link!=first);
cout<<last->data;
}
顺序表
SeqList.h
//
// Created by zhangzhiqiang on 2020/5/16.
//
#ifndef DATASTRUCTURE_SEQLIST_H
#define DATASTRUCTURE_SEQLIST_H
#include <cstdlib>
#include <iostream>
//顺序表
struct SeqList{
private:
int *data;//定义int型指针用于动态分配数组
int maxSize;//顺序表的最大容量
int last;//当前已存表项的最后位置(从0开始),表空时为-1
public:
SeqList(int size);//构造函数,size为初始化顺序表的大小
bool IsFull();//判满
bool IsEmpty();//判空
bool Insert(int i,int x);//将新元素x插入到第i个位置后面
bool Remove(int i,int &x);//删除第i个位置的元素,并通过引用类型x返回其值
void ReSize(int newSize);//扩充顺序表,使其新数组的元素个数为newSize
};
#endif //DATASTRUCTURE_SEQLIST_H
SeqList.cpp
//
// Created by zhang zhiqiang on 2021/9/11.
//
#include "SeqList.h"
//构造函数(初始化)
SeqList::SeqList(int size) {
maxSize=size;
last=-1;//设置表长为空
data=new int[size];
}
//判满
bool SeqList::IsFull() {
return last == maxSize - 1;
}
//判空
bool SeqList::IsEmpty() {
return last==-1;
}
//插入
bool SeqList::Insert(int i, int x) {
if(IsFull() || i<0 || i>last+1 ){//判表满、参数i是否合理,(i>last+1)表示只能顺序存储
return false;
}else{
for (int j = last; j >= i ; j--) {
data[j+1]=data[j];//先依次后移,空出第i号位置
}
data[i]=x;//这里注意,若定义数组 int a[10],表示10个元素,但使用数组时,下标是0~9
last++;//最后位置加1
return true;
}
}
//删除
bool SeqList::Remove(int i, int &x) {
if (IsEmpty() || i<1 ||i>last+1){//判表空、参数i是否合理
return false;
}else{
x=data[i-1];//保存第i个被删元素
for (int j = i; j <= last; j++) {
data[j-1]=data[j];//依次往前移,填补
}
last--;//最后位置减1
return true;
}
}
//扩充顺序表,新数组元素个数为newSize
void SeqList::ReSize(int newSize) {
if (newSize <= 0 || newSize == maxSize) {//检查参数的合理性
std::cout << "无效的数组大小\n";
} else {
int *newArray = new int[newSize];//建立新数组
int n = last + 1;//记录原数组长度为n
int *srcptr = data;//原数组首地址
int *destptr = newArray;//新数组首地址
while (n--) {
*destptr++ = *srcptr++;//复制元素
}
delete[]data;//删老数组
data = newArray;//复制新数组
maxSize = newSize;
}
}
带头结点的单链表
SinList.h
//
// Created by zhangzhiqiang on 2020/7/5.
//
#ifndef DATASTRUCTURE_SINLIST_H
#define DATASTRUCTURE_SINLIST_H
#include <iostream>
//单链表结点
struct LinkNode{
int data;//数据域
LinkNode *link;//指针域
};
//带头结点的单链表
class SinList{
private:
LinkNode *first;//指向头结点的指针
public:
SinList();//构造函数
bool Insert(int &x);//将新元素x插入
bool Remove(int i,int &x);//删除第i个位置的结点(i从1开始),将被删结点值通过引用类型x返回
void Print();
};
#endif //DATASTRUCTURE_SINLIST_H
SinList.cpp
//
// Created by zhang zhiqiang on 2021/9/11.
//
#include "SinList.h"
//附加头结点的单链表构造函数
SinList::SinList() {
LinkNode *headNode=new LinkNode;
headNode->link=nullptr;
first=headNode;
}
//插入新元素x
bool SinList::Insert(int &x) {
LinkNode *newNode=new LinkNode;//为新插入元素构造结点
newNode->data=x;//数据域为元素值
//将新结点放在头结点的后面(不必区分在单链表头部或中部、尾部插入)
newNode->link=first->link;
first->link=newNode;
return true;
}
//删除第i个位置的结点(i从1开始),将被删结点值通过引用类型x返回
bool SinList::Remove(int i, int &x) {
LinkNode *del;//被删结点的指针
LinkNode *current;//被删除结点的前一个结点
current=first;//先将结点指向头结点,然后遍历寻找第i个位置的前一个结点
for (int j = 0; j <i-1 ; ++j) {
current=current->link;
}
del=current->link;//保存被删除结点
current->link=del->link;//重新拉链
x=del->data;//保存被删结点元素
delete del;//删除del指向的结点
return true;
}