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

news2024/12/29 8:56:29

本专栏旨在通过使用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); // 输出 100

    ParamByPointer(&L2);
    printf("通过指针传递后的值: %d\n", L2.data); // 输出 200

    return 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++; // 线性表长度加1
    return 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++; // 线性表长度加1
    return 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--; // 线性表长度减1
    return 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--; // 线性表长度减1
    return 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++; // 线性表长度加1
    return 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--; // 线性表长度减1
    return 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 i
    return -1

def 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.coloradmin.cn/o/1602091.html

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

相关文章

查天气(Vue.js,Element UI)

演示图 几点注意 有亿点简陋&#xff0c;凑合能用&#xff0c;button一定要 !important 覆盖原本的 element ui &#xff0c;不然无效axios回调函数中 this 指向改变了&#xff0c;需要额外的保存一份服务器返回的数据比较复杂时&#xff0c;获取的时候需要注意层级结构method…

光伏电站智能勘探:无人机优势及流程详解

随着科技和互联网技术的不断发展&#xff0c;无人机在各个领域的应用越来越广泛&#xff0c;其中之一就是光伏电站智能勘探。利用无人机高清摄像头和传感器等设备&#xff0c;可以对光伏电站周边环境、日照情况、房屋状态进行全方面的勘探和记录&#xff0c;搭配卫星勘探、实地…

自动驾驶(八十四)---------中间件对比分析

很久没有写博客了&#xff0c;CSDN无故非法删了我第82篇&#xff0c;让我很恼火&#xff0c;一直提不起兴趣重新写一遍第82篇。但回初心&#xff0c;知识需要用自己的语言输出&#xff0c;所以今天对比分析自动驾驶中间件&#xff1a; 1. 中间件介绍 在自动驾驶架构中&#xf…

第14章 大数据与数据科学知识点梳理

第14章 大数据与数据科学知识点梳理&#xff08;附带页码&#xff09; ◼ 原则&#xff1a;组织应仔细管理与大数据源相关的元数据&#xff0c;以便对数据文件及其来源和价值进行准确的清单管理。P386 ◼ 大数据&#xff1a;数据量大&#xff08;Volume&#xff09;、数据更新…

嵌入式中C++指针使用方法总结

各位开发者大家好,在分享指针之前,先来看一下int *p[3]和int (*p)[3] 的区别。 int *p[3] p是一个数组,此数组有3个元素,每个元素都是int*类型,也就是指向整型数据的指针类型。 int a=10,b=20,c=30; int*p[3]={&a,&b,&c}; 而int(*p)[3]中的p是一个指向数组的…

浅谈Java的synchronized 锁以及synchronized 的锁升级

在Java中&#xff0c;synchronized关键字用于实现线程间的同步&#xff0c;确保同一时刻只有一个线程能够访问被同步的代码块或方法。当一个线程获得synchronized锁定后&#xff0c;其他试图访问同一锁的线程将被阻塞&#xff0c;直到锁被释放。 synchronized锁有两种基本形式…

计算机网络实验实验之VLAN的配置与分析

实验目的 了解什么是带内管理&#xff1b;熟练掌握如何使用telnet方式管理交换机&#xff1b;熟练掌握如何为交换机设置web方式管理&#xff1b;熟练掌握如何进入交换机web管理方式&#xff1b;了解交换机web配置界面&#xff0c;并能进行部分操作。 (6)了解VLAN原理&#xf…

python pygame事件与事件处理

本期是接上期python pygame库的略学内容最后一个步骤&#xff0c;游戏与玩家交互的内容。 一、什么是事件 游戏需要与玩家交互&#xff0c;因此它必须能够接收玩家的操作&#xff0c;并根据玩家的不同操作做出有针对性的响应。程序开发中将玩家会对游戏进行的操作称为事件&…

微服务架构与Dubbo

一、微服务架构 微服务架构是一种架构概念&#xff0c;旨在通过将功能分解到各个离散的服务中以实现对解决方案的解耦。 分布式系统式若干独立系统的集合&#xff0c;但是用户使用起来好像是在使用一套系统。 和微服务对应的是单体式开发&#xff0c;即所有的功能打包在一个WAR…

关于CRMEB 商城系统商业授权的那些事儿

现在&#xff0c;很多时候我们都会听到“授权”这个词&#xff0c;在CRMEB的商城系统产品中&#xff0c;商业授权也是一个重要环节&#xff0c;今天&#xff0c;我们就来了解一下关于CRMEB商城系统授权的那些事儿。 一、为什么要进行商业授权&#xff1f; 正版商业授权是对用户…

【Linux】详解如何利用共享内存实现进程间通信

一、共享内存&#xff08;Shared Memory&#xff09;的认识 共享内存&#xff08;Shared Memory&#xff09;是多进程间共享的一部分物理内存。它允许多个进程访问同一块内存空间&#xff0c;从而在不同进程之间共享和传递数据。这种方式常常用于加速进程间的通信&#xff0c;因…

软考130-上午题-【软件工程】-系统维护

一、系统维护概述 软件维护是软件生命周期中的最后一个阶段&#xff0c;处于系统投入生产性运行以后的时期中&#xff0c;因此不属于系统开发过程。 软件维护是在软件已经交付使用之后为了改正错误或满足新的需求而修改软件的过程&#xff0c;即软件在交付使用后对软件所做的一…

李沐-19 卷积层【动手学深度学习v2】

记录下关于权重下标变换的理解&#xff1a; 从原来的Wi,j到Wi,j,k,l是从二维到四维的过程&#xff0c;如下图所示 对全连接层使用平移不变性和局部性得到卷积层&#xff0c;这是卷积层的引入&#xff0c;下方Vi,j,a,b--->Va,b表示了平移不变性&#xff0c;给a,b限制在||内保…

C语言 【函数】

1.函数概述 函数是一种可重用的代码块&#xff0c;用于执行特定任务或完成特定功能 函数作用&#xff1a;对具备相同逻辑的代码进行封装&#xff0c;提高代码的编写效率&#xff0c;实现对代码的重用 2. 函数的使用 2.1 无参无返回值 #include <stdio.h>// 函数名…

光纤收发器的注意事项

光纤收发器有各种不同的类别&#xff0c;而实际使用中最受关注的是根据光纤收发器的不同类别&#xff1a;SC连接器光纤收发器和FC/ST连接器光纤收发器。 当使用光纤收发器连接到不同的设备时&#xff0c;必须小心使用不同的端口。 1.光纤收发器与100Base TX设备&#xff08;交…

IP定位技术原理详细阐述

IP定位技术原理主要基于IP地址与地理位置之间的关联&#xff0c;通过一系列的技术手段&#xff0c;实现对网络设备的物理位置进行精确或大致的定位。以下是对IP定位技术原理的详细阐述。 首先&#xff0c;我们需要了解IP地址的基本概念。IP地址是互联网协议地址的简称&#xff…

【leetcode】双指针算法技巧——滑动窗口

标题&#xff1a;【leetcode】双指针算法技巧——滑动窗口 水墨不写bug 正文开始&#xff1a; 滑动窗口介绍 滑动窗口是一种常用的算法技巧&#xff0c;用于解决一些涉及 连续子数组或子串 的问题。它的基本思想是 维护一个窗口&#xff0c;通过 在窗口内移动 来寻找满…

LeetCode刷题总结 | 图论3—并查集

并查集理论基础 1.背景 首先要知道并查集可以解决什么问题呢&#xff1f; 并查集常用来解决连通性问题。大白话就是当我们需要判断两个元素是否在同一个集合里的时候&#xff0c;我们就要想到用并查集。 并查集主要有两个功能&#xff1a; 将两个元素添加到一个集合中。判…

Day18_学点儿设计模式_MVC和三层架构

0 优质文章 MVC与三层架构 什么是MVC&#xff1f;什么是三层架构&#xff1f; 三层架构与MVC详细讲解 MVC三层架构&#xff08;详解&#xff09; 1 MVC MVC全名是Model View Controller&#xff0c;是模型(model)&#xff0d;视图(view)&#xff0d;控制器(controller)的缩写…

【Vue3】setup语法糖的使用

文章目录 setup简介使用vite-plugin-vue-setup-extend插件 指定组件名字 setup简介 <script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖 相比较普通的<script> ,它有以下优势&#xff1a; 更少的样板内容&#xff0c;更简洁的代码。能够使用纯…