【数据结构】顺序表的基本操作

1. 顺序表的定义与结构

顺序表是用一段地址连续的存储单元依次存储数据元素的线性结构,逻辑上相邻的元素在物理位置上也相邻。顺序表结构如下:

cpp 复制代码
typedef struct {
    ElemType *elem; // 指向存储空间的基地址(动态数组)
    int length;     // 顺序表当前长度(实际元素个数)
} SqList;
#define MAXSIZE 100  // 顺序表最大容量(最多存储100个元素)
  • elem:动态分配的数组,用于存储元素(物理上连续)。
  • length:记录当前元素个数,初始为 0,最大不超过MAXSIZE

2. 初始化算法(InitList)

功能:为顺序表分配存储空间,初始化表长为 0。

实现代码

cpp 复制代码
Status InitList(SqList &L) {
    L.elem = new ElemType[MAXSIZE]; // 动态分配大小为MAXSIZE的数组
    if (!L.elem) exit(OVERFLOW);    // 内存分配失败则退出程序
    L.length = 0;                   // 初始长度为0(空表)
    return OK;
}

关键细节

  • new动态分配数组空间,避免静态数组的固定大小限制。
  • 若内存分配失败(L.elemNULL),通过exit(OVERFLOW)终止程序,防止后续错误。
  • 初始化后,顺序表为 "空表"(length=0),但已占用MAXSIZE*sizeof(ElemType)的存储空间。

3. 取值算法(GetElem)

功能 :获取顺序表中第i个位置(位序)的元素值。

实现代码

cpp 复制代码
Status GetElem(SqList L, int i, ElemType &e) {
    if (i < 1 || i > L.length) return ERROR; // 位置i不合法
    e = L.elem[i - 1];                       // 第i个元素对应数组下标i-1
    return OK;
}

关键细节

  • 顺序表的 "位序" 从 1 开始(符合人类习惯),而数组下标从 0 开始,因此第i个元素在数组中的位置是i-1
  • 合法性检查:i必须满足1 ≤ i ≤ length(超出范围则返回ERROR)。
  • 时间复杂度:O(1)(直接通过下标访问,无需遍历)。

4. 查找算法(LocateElem)

功能 :根据元素值e查找其在顺序表中的位序(若存在,返回位序;否则返回 0)。

实现代码

cpp 复制代码
int LocateElem(SqList L, ElemType e) {
    for (int i = 0; i < L.length; i++) {
        if (L.elem[i] == e) return i + 1; // 找到元素,返回位序(下标+1)
    }
    return 0; // 未找到元素
}

关键细节

  • 采用顺序查找 (遍历数组),逐个比较元素值是否等于e
  • 找到时返回位序(i+1,因为i是数组下标),未找到返回 0。
  • 时间复杂度:O(n)n为表长,最坏情况需遍历所有元素)。

5. 插入算法(ListInsert)

功能 :在顺序表的第i个位置(位序)插入新元素e

实现代码

cpp 复制代码
Status ListInsert(SqList &L, int i, ElemType e) {
    if (i < 1 || i > L.length + 1) return ERROR; // 插入位置不合法
    if (L.length == MAXSIZE) return ERROR;       // 表已满,无法插入
    // 从后往前移动元素,为新元素腾出位置
    for (int j = L.length - 1; j >= i - 1; j--) {
        L.elem[j + 1] = L.elem[j];
    }
    L.elem[i - 1] = e; // 插入新元素
    L.length++;        // 表长加1
    return OK;
}

关键细节

  • 插入位置合法性i必须满足1 ≤ i ≤ length+1(可以插入到表首、表中或表尾)。
  • 表满检查 :若length == MAXSIZE,无法插入(顺序表容量固定)。
  • 元素后移 :从最后一个元素(下标length-1)开始,到第i-1个元素,依次后移一位(j+1),防止元素被覆盖。
  • 时间复杂度:O(n)(最坏情况插入到表首,需移动n个元素)。

6. 删除算法(ListDelete)

功能 :删除顺序表中第i个位置(位序)的元素。

实现代码

cpp 复制代码
Status ListDelete(SqList &L, int i) {
    if (i < 1 || i > L.length) return ERROR; // 删除位置不合法
    // 从被删除元素的下一个位置开始,依次前移覆盖
    for (int j = i; j <= L.length - 1; j++) {
        L.elem[j - 1] = L.elem[j];
    }
    L.length--; // 表长减1
    return OK;
}

关键细节

  • 删除位置合法性i必须满足1 ≤ i ≤ length(只能删除已存在的元素)。
  • 元素前移 :从被删除元素的下一个位置(下标i)开始,到最后一个元素(下标length-1),依次前移一位(j-1),覆盖被删除的元素。
  • 时间复杂度:O(n)(最坏情况删除表首元素,需移动n-1个元素)。

7. 打印算法(PrintList)

功能:遍历并输出顺序表中所有元素。

实现代码

cpp 复制代码
void PrintList(SqList L) {
    cout << "当前顺序表元素:";
    for (int i = 0; i < L.length; i++) {
        cout << L.elem[i] << " ";
    }
    cout << endl;
}

关键细节

  • 遍历数组从下标0length-1(仅输出已存储的元素,不包括未使用的空间)。
  • 时间复杂度:O(n)(需遍历所有元素)。

完整C++代码如下:

cpp 复制代码
#include<iostream>
using namespace std;

#define MAXSIZE 100  // 顺序表最大长度
typedef int ElemType;
typedef int Status;
#define OK 1
#define ERROR 0 
#define OVERFLOW -2

typedef struct {
    ElemType *elem; // 存储空间基地址
    int length;     // 顺序表当前长度
} SqList;

// 函数声明
Status InitList(SqList &L);          // 初始化顺序表
Status GetElem(SqList L, int i, ElemType &e); // 取值
int LocateElem(SqList L, ElemType e); // 查找
Status ListInsert(SqList &L, int i, ElemType e); // 插入
Status ListDelete(SqList &L, int i); // 删除
void PrintList(SqList L);            // 打印顺序表

int main() {
    SqList L;
    int i, e, n, result;

    // ===================== 1. 测试初始化 =====================
    cout << "============ 测试初始化操作 ============" << endl;
    if (InitList(L) == OK) {
        cout << "顺序表初始化成功!" << endl;
    } else {
        cout << "顺序表初始化失败!" << endl;
        return 1;
    }
    PrintList(L);

    // ===================== 2. 测试插入操作 =====================
    cout << "\n============ 测试插入操作 ============" << endl;
    cout << "请输入要插入的元素个数:";
    cin >> n;
    cout << "请依次输入" << n << "个元素(将插入到顺序表的1~" << n << "位置):" << endl;
    for (int k = 1; k <= n; k++) {
        cin >> e;
        if (ListInsert(L, k, e) == OK) {
            cout << "插入元素 " << e << " 到位置 " << k << " 成功!" << endl;
        } else {
            cout << "插入元素 " << e << " 到位置 " << k << " 失败!" << endl;
        }
    }
    PrintList(L);

    // ===================== 3. 测试取值操作 =====================
    cout << "\n============ 测试取值操作 ============" << endl;
    cout << "请输入要取值的位置i(1~" << L.length << "):";
    cin >> i;
    if (GetElem(L, i, e) == OK) {
        cout << "位置 " << i << " 的元素是:" << e << endl;
    } else {
        cout << "取值位置 " << i << " 不合法!" << endl;
    }

    // ===================== 4. 测试查找操作 =====================
    cout << "\n============ 测试查找操作 ============" << endl;
    cout << "请输入要查找的元素e:";
    cin >> e;
    result = LocateElem(L, e);
    if (result != 0) {
        cout << "元素 " << e << " 的位序是:" << result << endl;
    } else {
        cout << "未找到元素 " << e << "!" << endl;
    }

    // ===================== 5. 测试删除操作 =====================
    cout << "\n============ 测试删除操作 ============" << endl;
    cout << "请输入要删除的位置i(1~" << L.length << "):";
    cin >> i;
    if (ListDelete(L, i) == OK) {
        cout << "删除位置 " << i << " 的元素成功!" << endl;
        PrintList(L);
    } else {
        cout << "删除位置 " << i << " 不合法!" << endl;
    }

    // 释放动态分配的内存(防止内存泄漏)
    delete[] L.elem;
    return 0;
}

// 初始化顺序表
Status InitList(SqList &L) {
    L.elem = new ElemType[MAXSIZE]; // 动态分配数组空间
    if (!L.elem) exit(OVERFLOW);    // 内存分配失败则退出
    L.length = 0;                   // 空表长度初始化为0
    return OK;
}

// 取值:获取第i个位置的元素
Status GetElem(SqList L, int i, ElemType &e) {
    if (i < 1 || i > L.length) return ERROR; // 位置i不合法
    e = L.elem[i - 1];                       // 数组下标从0开始,第i个元素对应elem[i-1]
    return OK;
}

// 查找:返回元素e的位序(从1开始),未找到返回0
int LocateElem(SqList L, ElemType e) {
    for (int i = 0; i < L.length; i++) {
        if (L.elem[i] == e) return i + 1; // 找到元素,返回位序
    }
    return 0; // 查找失败
}

// 插入:在第i个位置插入元素e
Status ListInsert(SqList &L, int i, ElemType e) {
    if (i < 1 || i > L.length + 1) return ERROR; // 插入位置不合法
    if (L.length == MAXSIZE) return ERROR;       // 顺序表已满
    // 插入位置及之后的元素后移
    for (int j = L.length - 1; j >= i - 1; j--) {
        L.elem[j + 1] = L.elem[j];
    }
    L.elem[i - 1] = e; // 放入新元素
    L.length++;        // 表长加1
    return OK;
}

// 删除:删除第i个位置的元素
Status ListDelete(SqList &L, int i) {
    if (i < 1 || i > L.length) return ERROR; // 删除位置不合法
    // 被删除元素之后的元素前移
    for (int j = i; j <= L.length - 1; j++) {
        L.elem[j - 1] = L.elem[j];
    }
    L.length--; // 表长减1
    return OK;
}

// 打印顺序表所有元素
void PrintList(SqList L) {
    cout << "当前顺序表元素:";
    for (int i = 0; i < L.length; i++) {
        cout << L.elem[i] << " ";
    }
    cout << endl;
}

程序运行结果如下:

完整Python代码如下:

python 复制代码
# 定义常量(对应原C++的宏定义)
MAXSIZE = 100  # 顺序表最大容量
OK = 1
ERROR = 0
OVERFLOW = -2  # Python中列表初始化极少出现内存溢出,仅保留常量兼容逻辑


class SqList:
    """顺序表类:模拟原C++的结构体+函数集合"""
    def __init__(self):
        """初始化顺序表(对应原InitList函数)"""
        # 用列表模拟固定容量的数组,初始填充None(模拟空存储空间)
        self.elem = [None] * MAXSIZE
        self.length = 0  # 初始表长为0(空表)

    def GetElem(self, i):
        """取值操作:获取第i个位置(位序,1开始)的元素"""
        # 检查位置合法性:i必须在[1, 当前表长]范围内
        if i < 1 or i > self.length:
            return ERROR, None  # 失败:返回错误状态+空值
        # 数组下标从0开始,第i个元素对应下标i-1
        return OK, self.elem[i - 1]

    def LocateElem(self, e):
        """查找操作:返回元素e的位序(1开始),未找到返回0"""
        # 遍历当前已存储的元素(仅前length个)
        for idx in range(self.length):
            if self.elem[idx] == e:
                return idx + 1  # 找到:返回位序(下标+1)
        return 0  # 未找到

    def ListInsert(self, i, e):
        """插入操作:在第i个位置(位序)插入元素e"""
        # 1. 检查插入位置合法性:i必须在[1, 当前表长+1](可插在表首/表中/表尾)
        if i < 1 or i > self.length + 1:
            return ERROR
        # 2. 检查顺序表是否已满
        if self.length == MAXSIZE:
            return ERROR
        # 3. 元素后移:从最后一个元素到第i个元素,依次往后挪1位
        # (原C++的j从length-1到i-1,Python反向遍历实现相同逻辑)
        for j in range(self.length - 1, i - 2, -1):
            self.elem[j + 1] = self.elem[j]
        # 4. 插入新元素到第i个位置(对应下标i-1)
        self.elem[i - 1] = e
        # 5. 表长加1
        self.length += 1
        return OK

    def ListDelete(self, i):
        """删除操作:删除第i个位置(位序)的元素"""
        # 1. 检查删除位置合法性:i必须在[1, 当前表长](只能删已存在的元素)
        if i < 1 or i > self.length:
            return ERROR
        # 2. 元素前移:从第i+1个元素到最后一个元素,依次往前挪1位
        for j in range(i, self.length):
            self.elem[j - 1] = self.elem[j]
        # 3. 表长减1(无需手动清空最后一个元素,后续插入会覆盖)
        self.length -= 1
        return OK

    def PrintList(self):
        """打印顺序表:输出当前所有元素(对应原PrintList函数)"""
        # 仅打印前length个已存储的元素
        print("当前顺序表元素:", end="")
        for idx in range(self.length):
            print(self.elem[idx], end=" ")
        print()  # 换行


# -------------------------- 主程序:测试所有功能(对应原main函数) --------------------------
if __name__ == "__main__":
    # 1. 测试初始化
    print("============ 测试初始化操作 ============")
    L = SqList()  # 初始化顺序表(Python类实例化即完成初始化)
    print("顺序表初始化成功!")
    L.PrintList()  # 打印空表

    # 2. 测试插入操作
    print("\n============ 测试插入操作 ============")
    # 输入插入元素个数
    n = int(input("请输入要插入的元素个数:"))
    print(f"请依次输入{n}个元素(将插入到顺序表的1~{n}位置):")
    # 循环输入并插入元素
    for k in range(1, n + 1):
        e = int(input(f"请输入第{k}个元素:"))
        if L.ListInsert(k, e) == OK:
            print(f"插入元素 {e} 到位置 {k} 成功!")
        else:
            print(f"插入元素 {e} 到位置 {k} 失败!")
    L.PrintList()  # 打印插入后的表

    # 3. 测试取值操作
    print("\n============ 测试取值操作 ============")
    i = int(input(f"请输入要取值的位置i(1~{L.length}):"))
    status, e = L.GetElem(i)
    if status == OK:
        print(f"位置 {i} 的元素是:{e}")
    else:
        print(f"取值位置 {i} 不合法!")

    # 4. 测试查找操作
    print("\n============ 测试查找操作 ============")
    e = int(input("请输入要查找的元素e:"))
    result = L.LocateElem(e)
    if result != 0:
        print(f"元素 {e} 的位序是:{result}")
    else:
        print(f"未找到元素 {e}!")

    # 5. 测试删除操作
    print("\n============ 测试删除操作 ============")
    i = int(input(f"请输入要删除的位置i(1~{L.length}):"))
    if L.ListDelete(i) == OK:
        print(f"删除位置 {i} 的元素成功!")
        L.PrintList()  # 打印删除后的表
    else:
        print(f"删除位置 {i} 不合法!")

    # Python无需手动释放内存(垃圾回收机制自动处理)

程序运行结果如下:

python 复制代码
============ 测试初始化操作 ============
顺序表初始化成功!
当前顺序表元素:

============ 测试插入操作 ============
请输入要插入的元素个数:6
请依次输入6个元素(将插入到顺序表的1~6位置):
请输入第1个元素:23
插入元素 23 到位置 1 成功!
请输入第2个元素:12
插入元素 12 到位置 2 成功!
请输入第3个元素:67
插入元素 67 到位置 3 成功!
请输入第4个元素:10
插入元素 10 到位置 4 成功!
请输入第5个元素:76
插入元素 76 到位置 5 成功!
请输入第6个元素:90
插入元素 90 到位置 6 成功!
当前顺序表元素:23 12 67 10 76 90 

============ 测试取值操作 ============
请输入要取值的位置i(1~6):4
位置 4 的元素是:10

============ 测试查找操作 ============
请输入要查找的元素e:67
元素 67 的位序是:3

============ 测试删除操作 ============
请输入要删除的位置i(1~6):5
删除位置 5 的元素成功!
当前顺序表元素:23 12 67 10 90 

完整Java代码如下:

java 复制代码
import java.util.Scanner;

// 顺序表类:封装顺序表的结构和操作
class SqList {
    // 常量定义(对应原C++的宏)
    public static final int MAXSIZE = 100;  // 顺序表最大容量
    public static final int OK = 1;         // 操作成功状态
    public static final int ERROR = 0;      // 操作失败状态
    public static final int OVERFLOW = -2;  // 内存溢出状态(Java中仅作兼容)

    private int[] elem;  // 存储元素的数组(对应原C++的ElemType* elem)
    private int length;  // 顺序表当前长度(对应原C++的length)

    // 构造函数:初始化顺序表(对应原C++的InitList函数)
    public SqList() {
        try {
            this.elem = new int[MAXSIZE];  // 初始化数组(模拟动态分配)
            this.length = 0;               // 初始表长为0(空表)
        } catch (OutOfMemoryError e) {
            // 模拟内存分配失败(对应原C++的exit(OVERFLOW))
            throw new IllegalStateException("顺序表初始化失败:内存溢出", e);
        }
    }

    /**
     * 取值操作:获取第i个位置(位序,1开始)的元素
     * @param i 目标位置(位序)
     * @return 结果数组:index0=状态(OK/ERROR),index1=元素值(仅状态为OK时有效)
     */
    public int[] getElem(int i) {
        int[] result = new int[2];  // 用数组封装状态和返回值(替代C++的引用传参)
        // 检查位置合法性:i必须在[1, 当前表长]范围内
        if (i < 1 || i > this.length) {
            result[0] = ERROR;
            return result;
        }
        // 数组下标从0开始,第i个元素对应下标i-1
        result[0] = OK;
        result[1] = this.elem[i - 1];
        return result;
    }

    /**
     * 查找操作:返回元素e的位序(1开始),未找到返回0
     * @param e 目标元素
     * @return 位序(找到)或0(未找到)
     */
    public int locateElem(int e) {
        // 遍历当前已存储的元素(仅前length个)
        for (int idx = 0; idx < this.length; idx++) {
            if (this.elem[idx] == e) {
                return idx + 1;  // 位序=下标+1
            }
        }
        return 0;  // 未找到
    }

    /**
     * 插入操作:在第i个位置(位序)插入元素e
     * @param i 插入位置(位序)
     * @param e 待插入元素
     * @return 状态(OK/ERROR)
     */
    public int listInsert(int i, int e) {
        // 1. 检查插入位置合法性:i必须在[1, 表长+1](可插在表首/表中/表尾)
        if (i < 1 || i > this.length + 1) {
            return ERROR;
        }
        // 2. 检查顺序表是否已满
        if (this.length == MAXSIZE) {
            return ERROR;
        }
        // 3. 元素后移:从最后一个元素到第i个元素,依次后挪1位(反向遍历)
        for (int j = this.length - 1; j >= i - 1; j--) {
            this.elem[j + 1] = this.elem[j];
        }
        // 4. 插入新元素到目标位置
        this.elem[i - 1] = e;
        // 5. 表长加1
        this.length++;
        return OK;
    }

    /**
     * 删除操作:删除第i个位置(位序)的元素
     * @param i 删除位置(位序)
     * @return 状态(OK/ERROR)
     */
    public int listDelete(int i) {
        // 1. 检查删除位置合法性:i必须在[1, 表长](只能删已存在的元素)
        if (i < 1 || i > this.length) {
            return ERROR;
        }
        // 2. 元素前移:从第i+1个元素到最后一个元素,依次前挪1位(正向遍历)
        for (int j = i; j < this.length; j++) {
            this.elem[j - 1] = this.elem[j];
        }
        // 3. 表长减1(无需清空最后一个元素,后续插入会覆盖)
        this.length--;
        return OK;
    }

    /**
     * 打印操作:输出当前顺序表的所有元素
     */
    public void printList() {
        System.out.print("当前顺序表元素:");
        for (int idx = 0; idx < this.length; idx++) {
            System.out.print(this.elem[idx] + " ");
        }
        System.out.println();
    }

    // 获取当前表长(供测试时判断合法位置)
    public int getLength() {
        return this.length;
    }
}

// 测试主类(对应原C++的main函数)
public class SqListTest {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        SqList L = new SqList();  // 初始化顺序表(调用构造函数)
        int i, e, n, result;

        // 1. 测试初始化(构造函数已完成,仅验证并打印)
        System.out.println("============ 测试初始化操作 ============");
        System.out.println("顺序表初始化成功!");
        L.printList();

        // 2. 测试插入操作
        System.out.println("\n============ 测试插入操作 ============");
        System.out.print("请输入要插入的元素个数:");
        n = scanner.nextInt();
        System.out.println("请依次输入" + n + "个元素(将插入到顺序表的1~" + n + "位置):");
        for (int k = 1; k <= n; k++) {
            e = scanner.nextInt();
            if (L.listInsert(k, e) == SqList.OK) {
                System.out.println("插入元素 " + e + " 到位置 " + k + " 成功!");
            } else {
                System.out.println("插入元素 " + e + " 到位置 " + k + " 失败!");
            }
        }
        L.printList();

        // 3. 测试取值操作
        System.out.println("\n============ 测试取值操作 ============");
        System.out.print("请输入要取值的位置i(1~" + L.getLength() + "):");
        i = scanner.nextInt();
        int[] getResult = L.getElem(i);
        if (getResult[0] == SqList.OK) {
            System.out.println("位置 " + i + " 的元素是:" + getResult[1]);
        } else {
            System.out.println("取值位置 " + i + " 不合法!");
        }

        // 4. 测试查找操作
        System.out.println("\n============ 测试查找操作 ============");
        System.out.print("请输入要查找的元素e:");
        e = scanner.nextInt();
        result = L.locateElem(e);
        if (result != 0) {
            System.out.println("元素 " + e + " 的位序是:" + result);
        } else {
            System.out.println("未找到元素 " + e + "!");
        }

        // 5. 测试删除操作
        System.out.println("\n============ 测试删除操作 ============");
        System.out.print("请输入要删除的位置i(1~" + L.getLength() + "):");
        i = scanner.nextInt();
        if (L.listDelete(i) == SqList.OK) {
            System.out.println("删除位置 " + i + " 的元素成功!");
            L.printList();
        } else {
            System.out.println("删除位置 " + i + " 不合法!");
        }

        scanner.close();  // 关闭输入流
    }
}

程序运行结果如下:

java 复制代码
============ 测试初始化操作 ============
顺序表初始化成功!
当前顺序表元素:

============ 测试插入操作 ============
请输入要插入的元素个数:6
请依次输入6个元素(将插入到顺序表的1~6位置):
23
插入元素 23 到位置 1 成功!
12
插入元素 12 到位置 2 成功!
67
插入元素 67 到位置 3 成功!
10
插入元素 10 到位置 4 成功!
76
插入元素 76 到位置 5 成功!
90
插入元素 90 到位置 6 成功!
当前顺序表元素:23 12 67 10 76 90 

============ 测试取值操作 ============
请输入要取值的位置i(1~6):4
位置 4 的元素是:10

============ 测试查找操作 ============
请输入要查找的元素e:67
元素 67 的位序是:3

============ 测试删除操作 ============
请输入要删除的位置i(1~6):5
删除位置 5 的元素成功!
当前顺序表元素:23 12 67 10 90 

总结:顺序表的核心特性

  1. 优点

    • 支持随机访问(通过下标直接访问元素,时间复杂度O(1))。
    • 存储密度高(无需额外存储指针,仅需存储元素本身)。
  2. 缺点

    • 容量固定(受MAXSIZE限制,动态扩容成本高)。
    • 插入 / 删除操作需移动大量元素(时间复杂度O(n))。
  3. 适用场景:适用于元素个数固定、频繁查询、较少插入 / 删除的场景。

相关推荐
元亓亓亓2 小时前
LeetCode热题--207. 课程表--中等
算法·leetcode·职场和发展
坚持编程的菜鸟2 小时前
LeetCode每日一题——有效的字母异位词
c语言·算法·leetcode
未知陨落2 小时前
LeetCode:70.最小栈
数据结构·算法·leetcode
小糖学代码2 小时前
STL的list模拟实现(带移动构造和emplace版本)
c语言·数据结构·c++·windows·list
jikiecui3 小时前
信奥崔老师:常用编译命令g++的基本使用
算法
王嘉俊9253 小时前
Qt 入门:构建跨平台 GUI 应用的强大框架
c语言·开发语言·c++·qt·入门·cpp
老歌老听老掉牙3 小时前
OpenCASCADE 点云拟合曲线与曲面:从零实现到工业级应用
c++·点云·opencascade
shenghaide_jiahu3 小时前
leetcode430:扁平化多级双向链表
数据结构·链表
失散133 小时前
软件设计师——03 数据结构(上)
数据结构·软考·软件设计师