数据结构——线性表(核心操作,附代码)
文章目录
- 一、顺序表的核心操作
- 1.1定义及初始化
- 1.2遍历
- 1.3查(按值&按索引)
- 1.4增(指定索引)
- 1.5删(指定索引)
- 1.6改(指定索引)
- 二、链表的核心操作
- 2.1定义及初始化
- 2.2遍历
- 2.3查(按索引&按值)
- 2.4增
- 2.5删(按索引)
- 2.6改
一、顺序表的核心操作
顺序表是用一段地址连续的存储单元依次存储线性表中的元素,元素的逻辑顺序与物理存储顺序完全一致。
底层依赖数组实现。特点是能通过数组下标直接访问元素。
1.1定义及初始化
max_size
表示顺序表的最大容量,即有有多少个元素。length
表示当前元素的个数,其范围为【0,max_size】index
表示数组的有效索引,其范围为【0,length-1】
#define MAX_SIZE 100 struct SeqList {int data [MAX_SIZE]; int length;
};
简单操作包括:初始化链表,判空,判满,获取长度。
// 初始化顺序表
void initList (SeqList& list) {list.length = 0; // 初始为空表
}
// 判断顺序表是否为空
bool isEmpty (const SeqList& list) {return list.length == 0;
}
// 判断顺序表是否已满
bool isFull (const SeqList& list) {return list.length == MAX_SIZE;
}
// 获取顺序表长度
int getLength (const SeqList& list) {return list.length;
}
1.2遍历
遍历即通过数组下标从 0 到 length-1 依次访问元素。
// 打印顺序表元素
void printList (const SeqList& list) {if (isEmpty (list)) return ;for (int i = 0; i <= list.length-1; ++i) {cout << list.data [i] << " ";}
}
1.3查(按值&按索引)
按索引查找
非常快,无需遍历,直接通过数组下标(索引)进行访问。注意索引范围。时间复杂度O(1)。
- length的范围为【0,max_size】
- 数组的有效索引的范围为【0,length-1】
按值查找
需要遍历整个顺序表,逐个比较当前元素值与目标值,找到匹配项后,返回数组下标。时间复杂度O(n)。
// 按索引查找元素
int getElement(const SeqList& list, int index) {if (index < 0 || index >= list.length) throw out_of_range("索引越界");return list.data[index]; // 直接访问数组对应下标
}
// 按值查找元素,返回第一个匹配元素的索引,未找到返回 - 1
int findElement(const SeqList& list, int value) {for (int i = 0; i < list.length; ++i) { // 遍历所有元素if (list.data[i] == value) {return i; // 找到后返回索引}}return -1; // 遍历结束未找到
}
1.4增(指定索引)
在指定索引 index 处插入一个新元素,后续元素依次后移。
void insertElement(SeqList& list, int index, int value) {if (isFull(list)) throw runtime_error("表满"); // 检查容量if (index < 0 || index > list.length) throw out_of_range("位置无效");// 从最后一个元素开始,依次后移一位(避免覆盖)for (int i = list.length-1; i >= index; --i) {list.data[i+1] = list.data[i];}list.data[index] = value; // 插入新元素list.length++; // 长度+1
}
1.5删(指定索引)
删除指定索引 index 处的元素,后续元素依次前移。
void deleteElement(SeqList& list, int index) {if (isEmpty(list)) throw runtime_error("表空"); // 检查空表if (index < 0 || index >= list.length) throw out_of_range("位置无效");// 从删除位置的下一个元素开始,依次前移一位(覆盖被删除元素)for (int i = index+1; i <= list.length-1; ++i) {list.data[i-1] = list.data[i];}list.length--; // 长度-1
}
1.6改(指定索引)
将指定索引 index 处的元素值修改为 newValue。【直接覆盖】
void updateElement(SeqList& list, int index, int newValue) {if (index < 0 || index >= list.length) throw out_of_range("修改位置无效");list.data[index] = newValue; // 直接覆盖旧值
}
二、链表的核心操作
2.1定义及初始化
ListNode
结构体定义:值val和指向下一个节点的指针nextdummy
:虚拟头结点,指向开始节点简化边界情况dummy->next
:开始节点,第一个存储有效数据的节点length
:记录链表长度
// 链表节点结构体
struct ListNode {int val;ListNode* next;// 构造函数ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode* n) : val(x), next(n) {}
};
ListNode* dummy; // 虚拟头节点(所有操作的统一起点)
int length; // 链表长度
// 初始化链表
LinkedList() {dummy = new ListNode(0); // 虚拟头节点,值无实际意义length = 0;
}
2.2遍历
void printList() {ListNode* h = dummy->next;//h指向开始节点if (h == nullptr) return ;while (h != nullptr) {cout << h->val << " -> ";h = h->next;}
}
2.3查(按索引&按值)
// 按索引获取元素
int get(int index) {// 索引无效检查if (index < 0 || index >= length) throw out_of_range("索引越界:无效的查询索引");ListNode* cur = dummy;//h指向头结点// 从头结点出发,移动index+1次到达目标节点for (int i = 0; i <= index; ++i) {cur = cur->next;}//执行完后,cur 指向的是 index 对应的节点return cur->val;
}
// 按值查找,返回第一个匹配元素的索引,未找到返回-1
int find(int value) {ListNode* cur = dummy->next; // 从真实头节点开始遍历for (int i = 0; i < length; ++i) {if (cur->val == value) return i; cur = cur->next;}return -1;
}
2.4增
插入的核心操作:
// 在指定索引处插入元素
void addAtIndex(int index, int val) {// 索引无效检查(允许index=length,即尾部插入)if (index < 0 || index > length) throw out_of_range("插入位置无效");ListNode* cur = dummy;// 从dummy出发,移动到达插入位置的前一个节点index-1for (int i = 0; i <= index-1; ++i) {cur = cur->next;}// 创建新节点并插入ListNode* newNode = new ListNode(val);newNode->next = cur->next; cur->next = newNode; length++;
}
- 头部插入等价于在索引 0 处插入
- 尾部插入等价于在索引 length 处插入
2.5删(按索引)
删除的核心操作
// 删除指定索引处的元素
void deleteAtIndex(int index) {if (index < 0 || index >= length) throw out_of_range("删除位置无效");ListNode* cur = dummy;// 从dummy出发,移动到达删除位置的前一个节点for (int i = 0; i <= index-1; ++i) {cur = cur->next;}// 保存待删除节点,修改指针,释放内存ListNode* temp = cur->next;cur->next = cur->next->next; // 跳过待删除节点delete temp; // 释放内存,避免泄漏length--;
}
2.6改
// 修改指定索引处的元素值
void updateAtIndex(int index, int newValue) {if (index < 0 || index >= length) throw out_of_range("修改位置无效");ListNode* cur = dummy;// 从dummy出发,移动到达目标节点index处for (int i = 0; i <= index; ++i) {cur = cur->next;}cur->val = newValue; // 修改值
}
设计链表
https://leetcode.cn/problems/design-linked-list/?envType=problem-list-v2&envId=linked-list