本文已参与「新人创作礼」活动,一起开启掘金创作之路。
GitHub同步更新(已分类):Data_Structure_And_Algorithm-Review
公众号:URLeisure 的复习仓库 公众号二维码见文末
以下是本篇文章正文内容,下面案例可供参考。
前言
大二在读学生,趁着寒假赶紧再学一遍数据结构,文章仅用作复习。前几篇文章都是基础中的基础。如果有大佬发现错误,还望斧正。什么是顺序表?
-
采用顺序存储的线性表称为顺序表。
-
顺序表采用顺序存储方式,即逻辑上相邻的数据在计算机内的存储位置也是相邻的。
-
根据分配空间方法不同,顺序表可以分为静态分配和动态分配两种。
-
静态分配:
- 使用一个定长数组date[]存储数据,最大空间为Maxsize,用length记录实际的元素个数,即顺序表的长度。
- 采用静态分配方法,定长数组需要预先分配一段固定大小的连续空间,但是在运算的过程中,如合并、插入等操作,容易超过预分配的空间长度,出现溢出。
-
动态分配:
- 在程序运行过程中,根据需要动态分配一段连续的空间(大小为Maxsize),用elem记录该空间的基地址(首地址),用length记录实际的元素个数,即顺序表的长度。
下面以动态分配空间的方法为例,分别介绍顺序表的初始化、创建、取值、查找、插入、删除等基本操作。(括号中文字对应java)
顺序表的基本操作
首先定义一个结构体(内部类),包含基地址与length。
c++代码如下(示例):
struct SqList{
int *elem;
int length;//顺序表长度
};
java代码如下(示例):
public class Ele{
int []elem;
int length;//顺序表长度
}
初始化
为顺序表分配一段预定义大小的连续空间,用elem记录这段空间的基地址,当前空间内没有任何数据元素,因此元素的实际个数为0。
c++代码如下(示例):
bool InitList(SqList &L){//为了实现形参改变实参,使用引用
L.elem = new int[Maxsize];
L.length = 0;
if(!L.elem){//添加鲁棒,判断是否成功
return false;
}
return true;
}
java代码如下(示例):
public boolean initList(){
s = new Ele();
s.elem = new int[maxsize];
if(s.elem == null)//添加鲁棒,判断是否成功
return false;
s.length = 0;
return true;
}
创建
向顺序表中输入数据,输入数据的类型必须与类型定义中的类型一致。在创建过程中,输入-1结束。
c++代码如下(示例):
bool CreateList(SqList &L){
int e,i = 0;
cin >> e;
while(e != -1){
if(L.length == Maxsize){//鲁棒
cout<<"顺序表已满"<<endl;
return false;
}
L.elem[i++] = e;
L.length++;
cin >> e;
}
return true;
}
java代码如下(示例):
public boolean createList(){
int e,i = 0;
e = input.nextInt();
while(e != -1){
if(s.length == maxsize){//鲁棒
System.out.println("顺序表已满");
return false;
}
s.elem[i++] = e;
s.length++;
e = input.nextInt();
}
return true;
}
取值
顺序表中任何一个元素都可以立即找到,称为随机存取方式。例如,要取第i个元素,只要i值是合法的(1 ≤ i ≤ L.length),那么立即就可以找到该元素。
c++代码如下(示例):
bool GetElem(SqList L,int i,int &e){//i 为查找的第几个元素,e为此元素的值
if(i<1 || i>L.length){
return false;
}
e = L.elem[i-1];//索引从0开始,因此 -1
return true;
}
java代码如下(示例):
public int getElem(int i){//i 为查找的第几个元素
if(i<1 || i>s.length){
return -1;
}
return s.elem[i-1];//索引从0开始,因此 -1
}
查找
查找一个元素e,可以从第一个元素开始顺序查找,依次比较每一个元素值。相等则返回元素位置(位序,即第几个元素);如果没有找到,则返回-1。
c++代码如下(示例):
int LocateElem(SqList L,int e){//e 要查找的值
for(int i = 0; i < L.length; i++){
if(L.elem[i] == e)
return i+1;
}
return -1;
}
java代码如下(示例):
public int locateElem(int e){//e 要查找的值
for(int i = 0; i < s.length; i++){
if(s.elem[i] == e)
return i+1;
}
return -1;
}
插入
在顺序表第i个位置之前插入一个元素e,需要从最后一个元素开始,依次后移一位,直到把原来第i个元素也后移一位,再将e放入第i个位置。
代码如下(示例):
bool ListInsert(SqList &L,int i,int e){//i 要插入的位置,e 插入的元素值
if(i<1 || i>L.length){
return false;
}
if(L.length == Maxsize){//存储已满
return false;
}
for(int j = L.length - 1; j >= i - 1; j--){
L.elem[j+1] = L.elem[j];//从最后一个位置开始后移
}
L.elem[i-1] = e;
L.length++;
return true;
}
java代码如下(示例):
public boolean listInsert(int i,int e){//i 要插入的位置,e 插入的元素值
if(i<1 || i>s.length){
return false;
}
if(s.length == maxsize){//存储已满
return false;
}
for(int j = s.length - 1; j >= i - 1; j--){
s.elem[j+1] = s.elem[j];//从最后一个位置开始后移
}
s.elem[i-1] = e;
s.length++;
return true;
}
删除
在顺序表删除第i个元素,需要把该元素暂存到变量e中,然后从 i + 1 个元素开始依次前移,直到把最后一个元素也前移一位。
代码如下(示例):
bool ListDelete(SqList &L,int i,int &e){//e 记录要删除的元素
if (i<1 || i>L.length) {
return false;
}
e = L.elem[i-1];
for(int j = i; j <= L.length - 1; j++){
L.elem[j-1] = L.elem[j];
}
L.length--;
return true;
}
java代码如下(示例):
public int listDelete(int i){
int e;
if (i<1 || i>s.length) {
return -1;
}
e = s.elem[i-1];
for(int j = i; j <= s.length - 1; j++){
s.elem[j-1] = s.elem[j];
}
s.length--;
return e;
}
打印
c++代码如下(示例):
void PrintList(SqList L){
for(int i = 0; i < L.length; i++){
i==0 || printf(" ");//利用短路原理,使末尾不含空格
cout<<L.elem[i];
}
cout<<endl;
}
java代码如下(示例):
public void printList(){
for(int i = 0; i < s.length; i++){
System.out.print(s.elem[i]+" ");
}
System.out.println();
}
释放内存
c++需要手动释放内存,而java不需要。
c++代码如下(示例):
void DestroyList(SqList &L){
if(L.elem){
delete []L.elem;
}
}
完整代码
c++代码如下(示例):
#include<iostream>
#define Maxsize 100
using namespace std;
struct SqList {
int *elem;
int length;
};
bool InitList(SqList &L) {
L.elem = new int[Maxsize];
L.length = 0;
if (!L.elem) {
return false;
}
return true;
}
bool CreateList(SqList &L) {
int e, i = 0;
cin >> e;
while (e != -1) {
if (L.length == Maxsize) {
cout << "顺序表已满" << endl;
return false;
}
L.elem[i++] = e;
L.length++;
cin >> e;
}
return true;
}
bool GetElem(SqList L, int i, int &e) {
if (i < 1 || i > L.length) {
return false;
}
e = L.elem[i - 1];
return true;
}
int LocateElem(SqList L, int e) {
for (int i = 0; i < L.length; i++) {
if (L.elem[i] == e)
return i + 1;
}
return -1;
}
bool ListInsert(SqList &L, int i, int e) {
if (i < 1 || i > L.length) {
return false;
}
if (L.length == Maxsize) {
return false;
}
for (int j = L.length - 1; j >= i - 1; j--) {
L.elem[j + 1] = L.elem[j];
}
L.elem[i - 1] = e;
L.length++;
return true;
}
bool ListDelete(SqList &L, int i, int &e) {
if (i < 1 || i > L.length) {
return false;
}
e = L.elem[i - 1];
for (int j = i; j <= L.length - 1; j++) {
L.elem[j - 1] = L.elem[j];
}
L.length--;
return true;
}
void PrintList(SqList L) {
for (int i = 0; i < L.length; i++) {
i == 0 || printf(" ");
cout << L.elem[i];
}
cout << endl;
}
void DestroyList(SqList &L) {
if (L.elem) {
delete []L.elem;
}
}
int main() {
SqList L;
int i, e, x;
InitList(L);//初始化
CreateList(L);//输入 -1 结束
cin >> i;//得到第 i 个元素
GetElem(L, i, e);
cout << "第 " << i << " 个元素是" << e << endl;
cin >> x;//查找位置
cout << x << "在第 " << LocateElem(L, x) << " 个位置" << endl;
cin >> i >> e;//插入 位置-元素
ListInsert(L, i, e);
cin >> i;//删除
ListDelete(L, i, e);
PrintList(L);//打印
DestroyList(L);//释放空间
return 0;
}
java代码如下(示例):
import java.util.Scanner;
public class A {
private final int maxsize = 100;
private Ele s;
private static Scanner input = new Scanner(System.in);
public class Ele {
int[] elem;
int length;
}
public boolean initList() {
s = new Ele();
s.elem = new int[maxsize];
if (s.elem == null)
return false;
s.length = 0;
return true;
}
public boolean createList() {
int e, i = 0;
e = input.nextInt();
while (e != -1) {
if (s.length == maxsize) {
System.out.println("顺序表已满");
return false;
}
s.elem[i++] = e;
s.length++;
e = input.nextInt();
}
return true;
}
public int getElem(int i) {
if (i < 1 || i > s.length) {
return -1;
}
return s.elem[i - 1];
}
public int locateElem(int e) {
for (int i = 0; i < s.length; i++) {
if (s.elem[i] == e)
return i + 1;
}
return -1;
}
public boolean listInsert(int i, int e) {
if (i < 1 || i > s.length) {
return false;
}
if (s.length == maxsize) {
return false;
}
for (int j = s.length - 1; j >= i - 1; j--) {
s.elem[j + 1] = s.elem[j];
}
s.elem[i - 1] = e;
s.length++;
return true;
}
public int listDelete(int i) {
int e;
if (i < 1 || i > s.length) {
return -1;
}
e = s.elem[i - 1];
for (int j = i; j <= s.length - 1; j++) {
s.elem[j - 1] = s.elem[j];
}
s.length--;
return e;
}
public void printList() {
for (int i = 0; i < s.length; i++) {
System.out.print(s.elem[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
A a = new A();
int i, x;
a.initList();
a.createList();//输入 -1 结束
int e;
i = input.nextInt();//得到元素位置
e = a.getElem(i);
System.out.println("第i个元素是: " + e);
x = input.nextInt();//查找元素
System.out.println(x + "在第 " + a.locateElem(x) + " 个位置");
i = input.nextInt();//插入 位置-元素
e = input.nextInt();
a.listInsert(i, e);
i = input.nextInt();//删除
x = a.listDelete(i);
System.out.println(" 成功删除" + x);
a.printList();//打印
}
}
顺序表的优缺点
优点:
- 操作简单,存储密度高,可以随机存取,只需要O(1)的时间就可以取出第i个元素。
缺点:
- 需要预先分配最大空间,最大空间数估计过大或过小会造成空间浪费或溢出。插入和删除操作需要移动大量元素。
如果经常需要插入和删除操作,则顺序表的效率很低。为了克服该缺点,可以采用下一篇内容:链式存储- 单链表。
关注公众号,感受不同的阅读体验
下期预告: 单链表