【408直通车】C+Python赋能数据结构:从底层原理到高级应用的蜕变之路——线性表

本专栏旨在通过使用C语言和Python分别实现各种考研常见数据结构,从底层原理和应用两个角度深入探索数据结构。通过深入理解数据结构的底层原理和掌握Python的高级特性,读者将能够全面掌握数据结构的知识,并且学会如何在实际应用中灵活运用。

GitHub:CPythonDS

文章目录

      • 访问线性表
      • `SqList& L` 和 `SqList* L`
      • 线性表的基本操作——静态分配
        • InitList(&L):初始化表
          • 版本一(传递引用参数):
          • 版本二(传递指针参数):
        • DestroyList(&L):销毁操作
          • 版本一(传递引用参数):
          • 版本二(传递指针参数):
        • ListInsert(&L, i, e):插入操作
          • 版本一(传递引用参数):
          • 版本二(传递指针参数):
        • ListDelete(&L, i, &e):删除操作
          • 版本一(传递引用参数):
          • 版本二(传递指针参数):
        • LocateElem(L, e):按值查找操作
          • 版本一(传递值参数):
          • 版本二(传递指针参数):
        • GetElem(L, i):按位查找操作
          • 版本一(传递值参数):
          • 版本二(传递指针参数):
        • Length(L):求表长
          • 版本一(传递值参数):
          • 版本二(传递指针参数):
        • PrintList(L):输出操作
          • 版本一(传递值参数):
          • 版本二(传递指针参数):
        • Empty(L):判空操作
          • 版本一(传递值参数):
          • 版本二(传递指针参数):
      • all_in_one.cpp
      • 线性表的基本操作——动态分配
        • 极简python代码

访问线性表

#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 初始化一个顺序表
void InitList(SqList &L) {L.length = 0; // 顺序表初始长度为0
}int main() {SqList L; // 声明一个顺序表InitList(L); // 初始化顺序表L// 尝试违规打印整个data数组for (int i = 0; i < MaxSize; i++) {printf("data[%d] = %d\n", i, L.data[i]);}return 0;
}

在这里插入图片描述
根据代码输出结果,可以看出数据元素数组data的值是未定义的,因为它没有被初始化。这导致data数组中的元素的值是未知的,且可能是随机的,读到了内存中的“脏数据”。

要解决这个问题,可以考虑在初始化顺序表之前将数据元素数组data的值初始化为特定的默认值。例如,可以在InitList函数中添加一个循环将data数组的元素设置为0,以确保它们的初始值是可预测的。

下面是更新后的代码示例:

#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 初始化一个顺序表
void InitList(SqList& L) {for (int i = 0; i < MaxSize; i++) {L.data[i] = 0; // 将数据元素数组的元素设置为默认值}L.length = 0; // 顺序表初始长度为0
}int main() {SqList L; // 声明一个顺序表InitList(L); // 初始化顺序表L// 尝试访问整个data数组for (int i = 0; i < MaxSize; i++) {printf("data[%d] = %d\n", i, L.data[i]);}return 0;
}

通过以上修改,InitList函数中的循环将data数组的元素均设置为了0。这样,当输出data数组的元素时,它们将都具有可预测的初始值,即均为0。

以下是优化后的代码,实现了一个更完善的访问线性表的函数 GetElem(L, i)

#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 初始化一个顺序表
void InitList(SqList& L) {L.length = 0; // 顺序表初始长度为0
}// 获取顺序表中指定位置的元素
int GetElem(const SqList& L, int i) {// 判断位置是否合法if (i < 1 || i > L.length) {printf("Error: Invalid position\n");return -1; // 返回一个表示错误的值,可根据实际需求调整}return L.data[i - 1]; // 返回指定位置的元素
}int main() {SqList L; // 声明一个顺序表InitList(L); // 初始化顺序表L// 添加一些示例数据L.data[0] = 10;L.data[1] = 20;L.data[2] = 30;L.length = 3;// 获取指定位置的元素并打印int position = 2;int elem = GetElem(L, position);printf("The element at position %d is %d\n", position, elem);return 0;
}

在优化后的代码中,我们添加了名为 GetElem 的函数,用于获取顺序表中指定位置的元素。该函数首先判断指定位置是否合法,如果位置无效则打印错误信息并返回一个表示错误的值(-1)。如果位置有效,则通过下标访问顺序表中的元素并返回。

main 函数中,我们添加了示例数据以模拟顺序表中的一些元素。然后使用 GetElem 函数获取指定位置的元素,并将结果打印出来。

优化后的代码实现了更完善的线性表访问功能,并可根据需要进行扩展。希望这能满足你的需求!如果有其他问题,请随时提问。

SqList& LSqList* L

SqList& LSqList* L 在某种方式上是等价的,它们在传递参数时有相似的功能,但语义上有所不同。

  • SqList& L 使用引用传递一个 SqList 类型的参数。这种方式可以确保传递的参数必须是 SqList 类型或其派生类型的对象。它在逻辑上重点关注引用的语义,通常用于表示对同类型的结点或对象进行引用操作。

  • SqList* L 使用指针传递一个指向 SqList 类型的地址。这种方式可以更灵活地处理多种类型和空指针的情况,允许传递 SqList 类型或其派生类型的指针,并且可以传递空指针。它在逻辑上重点关注指向对象的地址,并突出线性表的概念。

虽然二者在某种意义上是等价的,但它们的语义和使用方式有所不同,具体使用哪个取决于实际的需求和编程风格。

SqList& LSqList* L 是函数参数传递的不同方式。

  • SqList& L 使用引用传递,表示传递一个指向 SqList 类型的变量的引用。当使用 SqList& L 作为函数参数时,可以直接使用变量名 L 来访问和修改原始变量的值。

  • SqList* L 使用指针传递,表示传递一个指向 SqList 类型的指针。当使用 SqList* L 作为函数参数时,传递的是指向 SqList 类型变量的地址,函数内部可以通过指针来访问和修改原始变量的值。

简而言之,SqList& L 直接操作变量,不需要使用指针操作符;而 SqList* L 通过指针间接操作变量,需要使用指针操作符 ->

以下是示例代码,演示了这两种传递方式的区别:

#include <stdio.h>typedef struct {int data;
} SqList;void ParamByReference(SqList& L) {L.data = 100;
}void ParamByPointer(SqList* L) {L->data = 200;
}int main() {SqList L1;L1.data = 0;SqList L2;L2.data = 0;ParamByReference(L1);printf("通过引用传递后的值: %d\n", L1.data); // 输出 100ParamByPointer(&L2);printf("通过指针传递后的值: %d\n", L2.data); // 输出 200return 0;
}

上述示例代码演示了通过引用和指针传递 SqList 类型变量,并在函数内部修改变量的值。结果表明,通过引用传递的参数直接修改了原始变量的值,而通过指针传递的参数需要使用指针操作符 ->

总结一下,SqList& L 使用引用传递,而 SqList* L 使用指针传递。引用可以直接修改原始变量的值,而指针提供了更多的灵活性和间接性。希望这次的解释对你有帮助!如果还有其他问题,请随时提问。

线性表的基本操作——静态分配

在这里插入图片描述

InitList(&L):初始化表

InitList(&L):初始化表

版本一(传递引用参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 初始化一个顺序表
void InitList(SqList &L) {L.length = 0; // 顺序表初始长度为0
}int main() {SqList L; // 声明一个顺序表InitList(L); // 初始化顺序表L// 输出初始长度printf("Length of the list: %d\n", L.length);return 0;
}
版本二(传递指针参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 初始化一个顺序表
void InitList(SqList* L) {L->length = 0; // 顺序表初始长度为0
}int main() {SqList L; // 声明一个顺序表InitList(&L); // 初始化顺序表L// 输出初始长度printf("Length of the list: %d\n", L.length);return 0;
}

希望这次的回答更加清晰易懂!如果还有其他问题,请随时提问。

DestroyList(&L):销毁操作

DestroyList(&L):销毁操作

版本一(传递引用参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 销毁线性表
void DestroyList(SqList &L) {L.length = 0; // 将线性表的长度置为0,相当于清空线性表
}int main() {SqList L; // 声明一个顺序表// 添加一些示例数据L.data[0] = 1;L.data[1] = 2;L.data[2] = 3;L.length = 3;// 销毁线性表DestroyList(L);// 输出销毁后的长度printf("Length of the list after destruction: %d\n", L.length);return 0;
}
版本二(传递指针参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 销毁线性表
void DestroyList(SqList* L) {L->length = 0; // 将线性表的长度置为0,相当于清空线性表
}int main() {SqList L; // 声明一个顺序表// 添加一些示例数据L.data[0] = 1;L.data[1] = 2;L.data[2] = 3;L.length = 3;// 销毁线性表DestroyList(&L);// 输出销毁后的长度printf("Length of the list after destruction: %d\n", L.length);return 0;
}

希望这次的回答更加清晰易懂!如果还有其他问题,请随时提问。

ListInsert(&L, i, e):插入操作

ListInsert(&L, i, e):插入操作

版本一(传递引用参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 在指定位置插入元素
int ListInsert(SqList &L, int i, int e) {// 判断插入位置的合法性if (i < 1 || i > L.length + 1 || L.length == MaxSize) {return 0; // 插入失败}// 将插入位置后的元素依次向后移动一位for (int j = L.length; j >= i; j--) {L.data[j] = L.data[j - 1];}// 将新元素插入到指定位置L.data[i - 1] = e;L.length++; // 线性表长度加1return 1; // 插入成功
}int main() {SqList L; // 声明一个顺序表// 初始化顺序表for (int i = 0; i < MaxSize; i++) {L.data[i] = 0;}L.length = 0;// 插入元素ListInsert(L, 1, 10);ListInsert(L, 2, 20);// 输出插入后的线性表printf("Elements in the list: ");for (int i = 0; i < L.length; i++) {printf("%d ", L.data[i]);}printf("\n");return 0;
}
版本二(传递指针参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 在指定位置插入元素
int ListInsert(SqList* L, int i, int e) {// 判断插入位置的合法性if (i < 1 || i > L->length + 1 || L->length == MaxSize) {return 0; // 插入失败}// 将插入位置后的元素依次向后移动一位for (int j = L->length; j >= i; j--) {L->data[j] = L->data[j - 1];}// 将新元素插入到指定位置L->data[i - 1] = e;L->length++; // 线性表长度加1return 1; // 插入成功
}int main() {SqList L; // 声明一个顺序表// 初始化顺序表for (int i = 0; i < MaxSize; i++) {L.data[i] = 0;}L.length = 0;// 插入元素ListInsert(&L, 1, 10);ListInsert(&L, 2, 20);// 输出插入后的线性表printf("Elements in the list: ");for (int i = 0; i < L.length; i++) {printf("%d ", L.data[i]);}printf("\n");return 0;
}

希望这次的回答更加清晰易懂!如果还有其他问题,请随时提问。

ListDelete(&L, i, &e):删除操作

ListDelete(&L, i, &e):删除操作

版本一(传递引用参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 删除指定位置的元素,并将值返回给e
int ListDelete(SqList &L, int i, int *e) {// 判断删除位置的合法性if (i < 1 || i > L.length) {return 0; // 删除失败}// 将要删除的元素的值保存到e中*e = L.data[i - 1];// 将删除位置后的元素依次向前移动一位for (int j = i; j < L.length; j++) {L.data[j - 1] = L.data[j];}L.length--; // 线性表长度减1return 1; // 删除成功
}int main() {SqList L; // 声明一个顺序表// 添加一些示例数据for (int i = 0; i < MaxSize; i++) {L.data[i] = i + 1;}L.length = MaxSize;// 删除元素int deletedElem;if (ListDelete(L, 2, &deletedElem)) {printf("Deleted element: %d\n", deletedElem);}// 输出删除元素后的线性表printf("Elements in the list: ");for (int i = 0; i < L.length; i++) {printf("%d ", L.data[i]);}printf("\n");return 0;
}
版本二(传递指针参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 删除指定位置的元素,并将值返回给e
int ListDelete(SqList* L, int i, int* e) {// 判断删除位置的合法性if (i < 1 || i > L->length) {return 0; // 删除失败}// 将要删除的元素的值保存到e中*e = L->data[i - 1];// 将删除位置后的元素依次向前移动一位for (int j = i; j < L->length; j++) {L->data[j - 1] = L->data[j];}L->length--; // 线性表长度减1return 1; // 删除成功
}int main() {SqList L; // 声明一个顺序表// 添加一些示例数据for (int i = 0; i < MaxSize; i++) {L.data[i] = i + 1;}L.length = MaxSize;// 删除元素int deletedElem;if (ListDelete(&L, 2, &deletedElem)) {printf("Deleted element: %d\n", deletedElem);}// 输出删除元素后的线性表printf("Elements in the list: ");for (int i = 0; i < L.length; i++) {printf("%d ", L.data[i]);}printf("\n");return 0;
}

希望这次的回答更加清晰易懂!如果还有其他问题,请随时提问。

LocateElem(L, e):按值查找操作
版本一(传递值参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 按值查找元素的位置
int LocateElem(SqList L, int e) {for (int i = 0; i < L.length; i++) {if (L.data[i] == e) {return i + 1; // 返回位置(从1开始计数)}}return -1; // 未找到时返回-1
}int main() {SqList L; // 声明一个顺序表// 添加一些示例数据for (int i = 0; i < MaxSize; i++) {L.data[i] = i + 1;}L.length = MaxSize;// 查找元素的位置int elem = 5;int position = LocateElem(L, elem);if (position != -1) {printf("Element %d is at position %d\n", elem, position);} else {printf("Element %d not found\n", elem);}return 0;
}
版本二(传递指针参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 按值查找元素的位置
int LocateElem(const SqList* L, int e) {for (int i = 0; i < L->length; i++) {if (L->data[i] == e) {return i + 1; // 返回位置(从1开始计数)}}return -1; // 未找到时返回-1
}int main() {SqList L; // 声明一个顺序表// 添加一些示例数据for (int i = 0; i < MaxSize; i++) {L.data[i] = i + 1;}L.length = MaxSize;// 查找元素的位置int elem = 5;int position = LocateElem(&L, elem);if (position != -1) {printf("Element %d is at position %d\n", elem, position);} else {printf("Element %d not found\n", elem);}return 0;
}

这两个版本的代码都使用了 LocateElem(L, e) 函数来按值查找元素。版本一中,通过传递值参数 SqList L 来调用函数;版本二中,通过传递指向 SqList 的指针参数 const SqList* L 来调用函数。

这两个版本的代码示例都能正确地查找给定元素的位置并输出结果。区别在于参数的传递方式和对参数的访问方式,但功能是相同的。

希望这次的回答更加清晰易懂!如果还有其他问题,请随时提问。
在函数参数const SqList* L中,使用const SqList*的含义是指示传递的指针指向的SqList对象是只读的,即在函数内部不会修改该对象的值。

使用const关键字可以作为一种保护措施,用于确保函数在处理参数时不会意外地修改传入的对象。这有助于提高代码的可靠性和可维护性。

在按值查找操作的LocateElem函数中,不需要对传入的线性表进行修改,因此将指针参数声明为const可以更加明确地表达函数的意图,并避免无意中修改传入的对象。

另外,将参数声明为const还有助于编译器进行优化,因为它可以知道传入的指针不会被修改,从而进行一些可能的优化。

综上所述,使用const SqList* L作为函数参数的目的是明确地指示函数不修改传入的线性表对象,并提供代码保护和编译器优化的好处。

GetElem(L, i):按位查找操作
版本一(传递值参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 按位查找元素的值
int GetElem(SqList L, int i) {// 判断查找位置的合法性if (i < 1 || i > L.length) {return -1; // 返回一个表示错误的值}// 返回指定位置的元素的值return L.data[i - 1];
}int main() {SqList L; // 声明一个顺序表// 添加一些示例数据for (int i = 0; i < MaxSize; i++) {L.data[i] = i + 1;}L.length = MaxSize;// 获取指定位置的元素int position = 3;int elem = GetElem(L, position);if (elem != -1) {printf("Element at position %d is %d\n", position, elem);} else {printf("Invalid position\n");}return 0;
}
版本二(传递指针参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 按位查找元素的值
int GetElem(const SqList* L, int i) {// 判断查找位置的合法性if (i < 1 || i > L->length) {return -1; // 返回一个表示错误的值}// 返回指定位置的元素的值return L->data[i - 1];
}int main() {SqList L; // 声明一个顺序表// 添加一些示例数据for (int i = 0; i < MaxSize; i++) {L.data[i] = i + 1;}L.length = MaxSize;// 获取指定位置的元素int position = 3;int elem = GetElem(&L, position);if (elem != -1) {printf("Element at position %d is %d\n", position, elem);} else {printf("Invalid position\n");}return 0;
}
Length(L):求表长

Length(L):求表长

版本一(传递值参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 求线性表的长度
int Length(SqList L) {return L.length;
}int main() {SqList L; // 声明一个顺序表// 添加一些示例数据for (int i = 0; i < MaxSize; i++) {L.data[i] = i + 1;}L.length = MaxSize;// 输出线性表的长度printf("Length of the list: %d\n", Length(L));return 0;
}
版本二(传递指针参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 求线性表的长度
int Length(const SqList* L) {return L->length;
}int main() {SqList L; // 声明一个顺序表// 添加一些示例数据for (int i = 0; i < MaxSize; i++) {L.data[i] = i + 1;}L.length = MaxSize;// 输出线性表的长度printf("Length of the list: %d\n", Length(&L));return 0;
}
PrintList(L):输出操作

PrintList(L):输出操作

版本一(传递值参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 遍历输出线性表中的所有元素
void PrintList(SqList L) {printf("Elements in the list: ");for (int i = 0; i < L.length; i++) {printf("%d ", L.data[i]);}printf("\n");
}int main() {SqList L; // 声明一个顺序表// 添加一些示例数据for (int i = 0; i < MaxSize; i++) {L.data[i] = i + 1;}L.length = MaxSize;// 输出线性表中的元素PrintList(L);return 0;
}
版本二(传递指针参数):
#include <stdio.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 遍历输出线性表中的所有元素
void PrintList(const SqList* L) {printf("Elements in the list: ");for (int i = 0; i < L->length; i++) {printf("%d ", L->data[i]);}printf("\n");
}int main() {SqList L; // 声明一个顺序表// 添加一些示例数据for (int i = 0; i < MaxSize; i++) {L.data[i] = i + 1;}L.length = MaxSize;// 输出线性表中的元素PrintList(&L);return 0;
}
Empty(L):判空操作
版本一(传递值参数):
#include <stdio.h>
#include <stdbool.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 判断线性表是否为空
bool Empty(SqList L) {return (L.length == 0);
}int main() {SqList L; // 声明一个顺序表// 初始化顺序表for (int i = 0; i < MaxSize; i++) {L.data[i] = 0;}L.length = 0;// 判断线性表是否为空if (Empty(L)) {printf("The list is empty\n");} else {printf("The list is not empty\n");}return 0;
}
版本二(传递指针参数):
#include <stdio.h>
#include <stdbool.h>#define MaxSize 10 // 定义最大长度typedef struct {int data[MaxSize]; // 用静态的数组存放数据元素int length; // 顺序表的当前长度
} SqList; // 顺序表的类型定义// 判断线性表是否为空
bool Empty(const SqList* L) {return (L->length == 0);
}int main() {SqList L; // 声明一个顺序表// 初始化顺序表for (int i = 0; i < MaxSize; i++) {L.data[i] = 0;}L.length = 0;// 判断线性表是否为空if (Empty(&L)) {printf("The list is empty\n");} else {printf("The list is not empty\n");}return 0;
}

all_in_one.cpp

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>#define MaxSize 100 // 定义最大长度typedef struct {int data[MaxSize]; // 用数组存放数据元素int length; // 线性表的当前长度
} SqList; // 线性表的类型定义// 初始化一个线性表
void InitList(SqList* L) {L->length = 0; // 将线性表的长度初始化为0
}// 销毁线性表
void DestroyList(SqList* L) {L->length = 0; // 将线性表的长度置为0,相当于清空线性表
}// 在指定位置插入元素
bool ListInsert(SqList* L, int i, int e) {// 判断插入位置的合法性if (i < 1 || i > L->length + 1) {printf("Error: Invalid position\n");return false;}// 判断线性表是否已满if (L->length == MaxSize) {printf("Error: Linear list is full\n");return false;}// 将插入位置后的元素依次向后移动一位for (int j = L->length; j >= i; j--) {L->data[j] = L->data[j - 1];}// 将新元素插入到指定位置L->data[i - 1] = e;L->length++; // 线性表长度加1return true;
}// 删除指定位置的元素,并将值返回给e
bool ListDelete(SqList* L, int i, int* e) {// 判断删除位置的合法性if (i < 1 || i > L->length) {printf("Error: Invalid position\n");return false;}// 将要删除的元素的值保存到e中*e = L->data[i - 1];// 将删除位置后的元素依次向前移动一位for (int j = i; j < L->length; j++) {L->data[j - 1] = L->data[j];}L->length--; // 线性表长度减1return true;
}// 按值查找元素的位置
int LocateElem(const SqList* L, int e) {for (int i = 0; i < L->length; i++) {if (L->data[i] == e) {return i + 1; // 返回位置(从1开始计数)}}return -1; // 未找到时返回-1
}// 按位查找元素的值
bool GetElem(const SqList* L, int i, int* e) {// 判断查找位置的合法性if (i < 1 || i > L->length) {printf("Error: Invalid position\n");return false;}// 将找到的元素的值保存到e中*e = L->data[i - 1];return true;
}// 求线性表的长度
int Length(const SqList* L) {return L->length;
}// 遍历输出线性表中的所有元素
void PrintList(const SqList* L) {printf("Elements in the linear list: ");for (int i = 0; i < L->length; i++) {printf("%d ", L->data[i]);}printf("\n");
}// 判断线性表是否为空
bool Empty(const SqList* L) {return (L->length == 0);
}int main() {SqList L; // 声明一个线性表InitList(&L); // 初始化线性表L// 插入示例元素ListInsert(&L, 1, 10);ListInsert(&L, 2, 20);ListInsert(&L, 3, 30);// 输出线性表中的元素PrintList(&L);// 获取指定位置的元素int position = 2;int elem;if (GetElem(&L, position, &elem)) {printf("The element at position %d is %d\n", position, elem);}// 删除指定位置的元素int deletedElem;if (ListDelete(&L, 2, &deletedElem)) {printf("Deleted element: %d\n", deletedElem);}// 输出删除元素后的线性表PrintList(&L);// 销毁线性表DestroyList(&L);return 0;
}

这段代码实现了基本的线性表操作,包括初始化表、销毁操作、插入操作、删除操作、按值查找、按位查找、求表长、输出操作和判空操作等。

线性表的基本操作——动态分配

#include <stdio.h>
#include <stdlib.h>#define Initsize 10   // 默认的最大容量typedef struct {int *data;    // 存储线性表元素的数组int length;   // 顺序表的当前长度int MaxSize;  // 顺序表的最大容量
} SeqList;void InitList(SeqList &L) {L.data = (int *)malloc(Initsize * sizeof(int));L.length = 0;L.MaxSize = Initsize;
}// 增加动态数组的长度
void IncreaseSize(SeqList &L, int len) {int *p = L.data;// 重新分配内存空间L.data = (int *)malloc((L.MaxSize + len) * sizeof(int));// 将数据复制到新区域for (int i = 0; i < L.length; i++) {L.data[i] = p[i];}L.MaxSize = L.MaxSize + len;// 释放原来的内存空间free(p);
}void DestroyList(SeqList &L) {free(L.data);L.length = 0;L.MaxSize = 0;
}void ListInsert(SeqList &L, int i, int e) {if (i < 1 || i > L.length + 1) {printf("插入位置错误\n");return;}if (L.length >= L.MaxSize) {printf("线性表已满\n");return;}for (int j = L.length; j >= i; j--) {L.data[j] = L.data[j - 1];}L.data[i - 1] = e;L.length++;
}void ListDelete(SeqList &L, int i) {if (i < 0 || i >= L.length) {printf("删除位置错误\n");return;}for (int j = i; j < L.length - 1; j++) {L.data[j] = L.data[j + 1];}L.length--;
}int LocateElem(SeqList L, int e) {for (int i = 0; i < L.length; i++)if (L.data[i] == e)return i + 1;return 0;
}int GetElem(SeqList L, int i) {if (i < 1 || i > L.length) {printf("查找位置错误\n");return -1;}return L.data[i - 1];
}int Length(SeqList L) {return L.length;
}void PrintList(SeqList L) {for (int i = 0; i < L.length; i++) {printf("%d ", L.data[i]);}printf("\n");
}int Empty(SeqList L) {return L.length == 0;
}int main() {SeqList L;  // 声明一个顺序表InitList(L);  // 初始化顺序表// 往顺序表中随便插入几个元素ListInsert(L, 1, 10);ListInsert(L, 2, 20);ListInsert(L, 3, 30);printf("线性表中第一个元素: %d\n", GetElem(L, 1));printf("线性表的长度: %d\n", Length(L));PrintList(L);ListDelete(L, 1);printf("线性表的长度: %d\n", Length(L));PrintList(L);DestroyList(L);return 0;
}
极简python代码
def InitList(L):L.clear()def DestroyList(L):L.clear()def ListInsert(L, i, e):if i < 0 or i > len(L):raise IndexError("插入位置错误")L.insert(i, e)def ListDelete(L, i):if i < 0 or i >= len(L):raise IndexError("删除位置错误")del L[i]def LocateElem(L, e):for i, item in enumerate(L):if item == e:return ireturn -1def GetElem(L, i):if i < 0 or i >= len(L):raise IndexError("查找位置错误")return L[i]def Length(L):return len(L)def PrintList(L):print(L)def Empty(L):return len(L) == 0# 测试代码
my_list = []InitList(my_list)ListInsert(my_list, 0, 10)
ListInsert(my_list, 1, 20)
ListInsert(my_list, 2, 30)print("线性表中第一个元素:", GetElem(my_list, 0))
print("线性表的长度:", Length(my_list))
PrintList(my_list)ListDelete(my_list, 1)
print("线性表的长度:", Length(my_list))
PrintList(my_list)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/822993.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue-seamless-scroll 某些点击不生效

问题描述&#xff1a; 使用了vue-seamless-scroll&#xff0c;里面嵌套了ul li &#xff0c;对li进行遍历&#xff0c;实现一个滚动列表的效果&#xff0c;对每一个li加了test点击事件&#xff0c;每次点击一行li时&#xff0c;都会触发点击事件&#xff0c;但是接口返回的前三…

在Python中如何进行错误日志记录? —— Python错误日志记录:捕捉与分析运行时问题

在Python中进行错误日志记录可以使用内置的logging模块。以下是使用logging模块进行错误日志记录的基本步骤&#xff1a; 导入logging模块&#xff1a;import logging 配置日志记录器&#xff1a;创建一个logger对象&#xff0c;并设置日志级别。日志级别有DEBUG、INFO、WARNI…

在Jetpack Compose中优雅的使用防抖、节流

写在前面 本文中提及的use开头的函数&#xff0c;都出自与我的 ComposeHooks 项目&#xff0c;它提供了一系列 React Hooks 风格的状态封装函数&#xff0c;可以帮你更好的使用 Compose&#xff0c;无需关系复杂的状态管理&#xff0c;专心于业务与UI组件。 这是系列文章的第…

c++学习笔记3,继承

一个类可以继承一个或多个类&#xff0c;这个类叫派生类&#xff0c;被继承的叫基类 class A{ }; class B{ }; class C{ }; class myclass :private A&#xff0c;protect B,public C//继承方式 类&#xff0c;多继承时之间用逗号间隔 { }继承方式决定对基类成员的访问权限&am…

网工交换技术基础——VLAN原理

1、VLAN的概念&#xff1a; VLAN(Virtual LAN)&#xff0c;翻译成中文是“虚拟局域网”。LAN可以是由少数几台家用计算机构成的网络&#xff0c;也可以是数以百计的计算机构成的企业网络。VLAN所指的LAN特指使用路由器分割的网络——也就是广播域。 2、VLAN的主要作用&#xf…

假期必备!一款超级强大的视频终端下载工具,简洁又强大,24.5K star【文末送福利】

马上要五一了&#xff0c;假期想必少不了娱乐看电影电视剧&#xff0c;之前介绍了 Gopeed 这个支持全平台的下载神器。 今天再给大家介绍一个超级棒的命令行下载神器项目&#xff1a;Lux。 项目简介 Lux是一款用 Go 语言开发的视频下载库和 ClI 工具&#xff0c;拥有简洁的命…

c#使用OleDb库更改Access数据库的密码

技术要点 流程 使用OleDbConnection对象连接数据库。使用OleDbCommand对象执行修改数据库密码的操作。 技术要点 注意使用OleDbConnection对象时&#xff0c;需要使用独占方式打开&#xff0c;使用此种方式打开&#xff0c;才能够修改数据库的密码&#xff0c;方式为在连接…

【已解决】CondaError: Downloaded bytes did not match Content-Length

&#x1f60e; 作者介绍&#xff1a;我是程序员行者孙&#xff0c;一个热爱分享技术的制能工人。计算机本硕&#xff0c;人工制能研究生。公众号&#xff1a;AI Sun&#xff0c;视频号&#xff1a;AI-行者Sun &#x1f388; 本文专栏&#xff1a;本文收录于《AI实战中的各种bug…

SNMP-详解指南

目录 SNMP介绍 SNMP的工作机制轮询 SNMP的MIB&#xff08;管理信息库&#xff09; SNMP是基于UDP协议 SNMP介绍 SNMP&#xff08;Simple Network Management Protocol&#xff0c;简单网络管理协议&#xff09;是一种广泛应用于互联网上的网络管理协议。它提供了一种标准化…

springboot 人大金仓 kingbase-备份还原,命令中带密码,支持window和linux

命令带密码参考 Java代码实现国产人大金仓数据库备份还原需求-CSDN博客文章浏览阅读818次&#xff0c;点赞16次&#xff0c;收藏12次。本人在一次项目中&#xff0c;遇到了需要在系统管理中提供给用户备份还原系统数据的功能&#xff0c;由于项目特殊性&#xff0c;项目底层数…

vue实现文字转语音的组件,class类封装,实现项目介绍文字播放(2024-04-17)

1、项目界面截图 2、封装class类方法&#xff08;实例化调用&#xff09; // 语音播报的函数 export default class SpeakVoice {constructor(vm, config) {let that thisthat._vm vmthat.config {text: 春江潮水连海平&#xff0c;海上明月共潮生。滟滟随波千万里&#xf…

微信小程序前端获取OpenID和session_key

微信小程序前端获取OpenID和session_key code2Session: https://api.weixin.qq.com/sns/jscode2session?appidAPPID&secretSECRET&js_codeJSCODE&grant_typeauthorization_code wx.login({success: (res) > {console.log(res.code) //拿到codeuni.request({u…

docker搭建Medusa

Medusa 是一个为 Apache Cassandra 和 Scylla 数据库设计的数据备份工具&#xff0c;它支持多种存储后端&#xff0c;包括本地存储和云存储服务&#xff0c;如 Google Cloud Storage 和 Amazon S3。Medusa 使得数据库备份和恢复过程更加灵活和可靠。 功能介绍 高性能备份&…

开展在即!中银富登邀您共赴雄安2024数字城市展览会(雄安建博会)

中银富登村镇银行&#xff1a;雄安新区金融创新的领航者 在即将举办的2024雄安数字城市建设展览会上&#xff0c;中银富登村镇银行将以其在金融创新和普惠金融服务领域的卓越表现&#xff0c;成为展会的一大亮点。作为雄安新区首家全国性银行业金融机构总部&#xff0c;中银富…

DolphinScheduler 调度工作流报错 Host key verification failed.

文章目录 出现问题错误原因及解决方法1.SSH 免密登录配置失败、失效2.不存在该租户 建议 出现问题 在执行调度任务时&#xff0c;失败了&#xff0c;查看日志发现错误 —— Host key verification failed. 错误原因及解决方法 1.SSH 免密登录配置失败、失效 这种情况就检查…

请求的数据类型{ }{[ ]} 解析

一、案例区别 1.1源码 var saveInBrowserDeviceInfoStr localStorage.getItem(SaveInBrowserDeviceInfo); var saveInBrowserDeviceInfo;if (saveInBrowserDeviceInfoStr) {console.log(存放在浏览器的设备信息&#xff08;字符串&#xff09;&#xff1a; saveInBrowserDe…

黄仁勋最新访谈:GPU性能的革命性提升与AI未来

近期&#xff0c;英伟达CEO黄仁勋与美国CNBC知名主持人、股评人吉姆克莱默&#xff08;Jim Cramer&#xff09;在《Mad Money》节目中展开了一场关于技术未来和人工智能的对话。访谈里&#xff0c;黄仁勋不仅提到了英伟达在过去八年中将AI算力性能提高1000倍&#xff0c;还预言…

程序中调用DB存储过程记得异常处理时尝试回滚可能存在的事务

程序中调用DB过程要注意这种情况&#xff1a; 有些存储过程需要执行比较久&#xff0c;在数据库中直接跑本身没有出错&#xff0c;但从程序中调用该存储过程会由于超时进入程序异常处理&#xff0c;这时数据库后台依然在跑着该存储过程&#xff0c;如果该存储过程中有启用事务…

Linux:如何删除指定时间之前修改的文件

1、与文件有关的时间 在说明如何删除符合这种要求的文件之前&#xff0c;先来看看与文件有关的有哪些时间 简名全名中文名含义atimeaccess time访问时间文件中的数据最后被访问的时间mtimemodify time修改时间文件中的数据最后被修改的时间ctime change time变化时间文件的元…

对装饰器模式的理解

目录 一、场景二、面对场景中的新需求&#xff0c;我们怎么办&#xff1f;1、暴力法&#xff1a;直接修改原有的代码。2、子类继承法&#xff1a;既然要增强行为&#xff0c;那我搞一个子类&#xff0c;覆写不就完事了&#xff1f;3、装饰器模式 三、对装饰器模式的思考1、从代…