1. 链表的插入删除
1. 单链表插入删除
图1. 单链表插入结点
图2. 单链表删除结点
#include <iostream>
typedef struct LNode {
int data;
struct LNode* next;
}LNode;
/// <summary>
/// 判断链表是否非空
/// </summary>
/// <param name="p"></param>
bool linkedListIsNotNull(LNode* p) {
if (p == NULL) {
return false;
}
return true;
}
/// <summary>
/// 遍历输出链表各个结点的值
/// </summary>
/// <param name="firstNode"></param>
void traverseLinkedList(LNode* p) {
while (p != NULL) {
// 对当前节点进行操作,打印节点的数据
printf("%d\n", p->data);
// 移动到下一个节点
p = p->next;
}
}
/// <summary>
/// 插入元素
/// </summary>
/// <param name="p">插入位置前面的元素</param>
/// <param name="q">要插入的元素</param>
void insertElement(LNode* p, LNode* q) {
q->next = p->next;
p->next = q;
}
/// <summary>
/// 删除元素
/// </summary>
/// <param name="p">要删除的元素的前一个元素</param>
/// <returns></returns>
LNode* deleteElement(LNode* p) {
LNode* q = p->next;
p->next = q->next;
q->next = NULL;
return q;
}
int main()
{
LNode* A;
A = new LNode;
LNode* B;
B = new LNode;
LNode* C;
C = new LNode;
A->data = 10;
B->data = 20;
C->data = 30;
A->next = B;
B->next = NULL;
C->next = NULL;
LNode* p = A;
LNode* q = C;
bool isNotNull = linkedListIsNotNull(p);
if (isNotNull) {
insertElement(p, q);
traverseLinkedList(p);
printf("---------------------------\n");
LNode* q = deleteElement(p);
free(q);
traverseLinkedList(p);
}
else {
printf("链表为空!");
}
}
代码1: 单链表的插入删除(没有考虑特殊情况)
特殊情况: 在链表的第一个结点之前插入结点或者删除第一个结点.
图3. 在含头结点的单链表的第一个结点之前插入结点
图4. 在不含头结点的单链表的第一个结点之前插入结点
图5. 含头结点的单链表删除第一个结点
图6. 不含头结点的单链表删除第一个结点
#include <iostream>
typedef struct LNode {
int data;
struct LNode* next;
}LNode;
/// <summary>
/// 判断链表是否非空
/// </summary>
/// <param name="p"></param>
bool linkedListIsNotNull(LNode* p) {
if (p == NULL) {
return false;
}
return true;
}
/// <summary>
/// 遍历输出链表各个结点的值
/// </summary>
/// <param name="firstNode"></param>
void traverseLinkedList(LNode* p) {
while (p != NULL) {
// 对当前节点进行操作,打印节点的数据
printf("%d\n", p->data);
// 移动到下一个节点
p = p->next;
}
}
/// <summary>
/// 插入元素
/// </summary>
/// <param name="p">插入位置前面的元素</param>
/// <param name="q">要插入的元素</param>
void insertElement(LNode* p, LNode* q) {
q->next = p->next;
p->next = q;
}
/// <summary>
/// 第一个结点之前插入元素
/// </summary>
/// <param name="p">第一个结点</param>
/// <param name="q">要插入的元素</param>
void insertFirstElement(LNode*& p, LNode* q) { //在C++中,指针类型属于值类型。这里需要改变p的值, 因此传递p的引用
q->next = p;
p = q;
printf("第一个数据: %d\n", p->data);
}
/// <summary>
/// 删除元素
/// </summary>
/// <param name="p">要删除的元素的前一个元素</param>
/// <returns></returns>
LNode* deleteElement(LNode* p) {
LNode* q = p->next;
p->next = q->next;
q->next = NULL;
return q;
}
/// <summary>
/// 删除第一个结点
/// </summary>
/// <param name="p">第一个结点</param>
/// <returns></returns>
LNode* deleteFirstElement(LNode*& p) { //在C++中,指针类型属于值类型。这里需要改变p的值, 因此传递p的引用
LNode* q = p;
p = p->next;
printf("删除的第一个数据: %d\n", q->data);
return q;
}
int main()
{
LNode* A;
A = new LNode;
LNode* B;
B = new LNode;
LNode* C;
C = new LNode;
A->data = 10;
B->data = 20;
C->data = 30;
A->next = B;
B->next = NULL;
C->next = NULL;
LNode* p = A;
LNode* q = C;
bool isNotNull = linkedListIsNotNull(p);
if (isNotNull) {
insertFirstElement(p, q);
traverseLinkedList(p);
printf("---------------------------\n");
LNode* q = deleteFirstElement(p);
free(q);
traverseLinkedList(p);
}
else {
printf("链表为空!");
}
}
代码2: 在不含头结点的单链表的第一个结点之前插入结点或者删除第一个结点.
需要注意的是, 在C++中,指针类型属于值类型。在第一个结点之前插入结点或者删除第一个结点的函数中需要改变p的值, 因此传递p的引用.
#include <iostream>
typedef struct LNode {
int data;
struct LNode* next;
}LNode;
/// <summary>
/// 判断链表是否非空
/// </summary>
/// <param name="p"></param>
bool linkedListIsNotNull(LNode* p) {
if (p == NULL) {
return false;
}
return true;
}
/// <summary>
/// 遍历输出链表各个结点的值
/// </summary>
/// <param name="firstNode"></param>
void traverseLinkedList(LNode* p) {
while (p != NULL) {
// 对当前节点进行操作,打印节点的数据
if (p->data != 0) {
printf("%d\n", p->data);
}
// 移动到下一个节点
p = p->next;
}
}
/// <summary>
/// 插入元素
/// </summary>
/// <param name="p">插入位置前面的元素</param>
/// <param name="q">要插入的元素</param>
void insertElement(LNode* p, LNode* q) {
q->next = p->next;
p->next = q;
}
/// <summary>
/// 删除元素
/// </summary>
/// <param name="p">要删除的元素的前一个元素</param>
/// <returns></returns>
LNode* deleteElement(LNode* p) {
LNode* q = p->next;
p->next = q->next;
q->next = NULL;
return q;
}
int main()
{
LNode* H;
H = new LNode;
LNode* A;
A = new LNode;
LNode* B;
B = new LNode;
LNode* C;
C = new LNode;
H->data = NULL;
A->data = 10;
B->data = 20;
C->data = 30;
H->next = A;
A->next = B;
B->next = NULL;
C->next = NULL;
LNode* p = H; //p指向头结点
LNode* q = C;
bool isNotNull = linkedListIsNotNull(p);
if (isNotNull) {
//第一个结点之前即头结点之后插入元素
insertElement(p, q);
traverseLinkedList(p);
printf("---------------------------\n");
//删除第一个结点, 即删除头结点之后的元素
LNode* q = deleteElement(p);
free(q);
traverseLinkedList(p);
}
else {
printf("链表为空!");
}
}
代码3: 在含头结点的单链表的第一个结点之前插入结点或者删除第一个结点.
可以看出: 给链表设置头结点, 可以使得在第一个数据结点之前插入一个新结点和删除第一个数据结点的操作同表中部结点的这些操作统一起来, 方便写代码; 带头结点的链表, 其头指针值不随操作而改变, 可以减少错误.
2. 双链表插入删除
图7. 双链表结点插入
图8. 双链表结点删除
#include <iostream>
typedef struct LNode {
int data;
struct LNode* next;
struct LNode* prior;
}LNode;
/// <summary>
/// 遍历输出链表各个结点的值
/// </summary>
/// <param name="firstNode"></param>
void traverseLinkedList(LNode* p) {
p = p->next;
while (p != NULL) {
// 对当前节点进行操作,打印节点的数据
printf("%d\n", p->data);
// 移动到下一个节点
p = p->next;
}
}
/// <summary>
/// 判断链表是否非空
/// </summary>
/// <param name="p"></param>
bool linkedListIsNotNull(LNode* p) {
if (p->next == NULL) {
return false;
}
return true;
}
/// <summary>
/// 插入元素
/// </summary>
/// <param name="p">插入位置前面的元素</param>
/// <param name="s">要插入的元素</param>
void insertElement(LNode* p, LNode* s) {
s->next = p->next;
s->prior = p;
p->next = s;
s->next->prior = s;
}
/// <summary>
/// 删除元素
/// </summary>
/// <param name="s">要删除的元素</param>
/// <returns></returns>
LNode* deleteElement(LNode* s) {
s->prior->next = s->next;
s->next->prior = s->prior;
s->next = NULL;
s->prior = NULL;
return s;
}
int main()
{
LNode* H;
H = new LNode;
LNode* A;
A = new LNode;
LNode* B;
B = new LNode;
LNode* C;
C = new LNode;
H->data = NULL;
A->data = 10;
B->data = 20;
C->data = 30;
H->next = A;
A->next = B;
B->next = NULL;
C->next = NULL;
H->prior = NULL;
A->prior = H;
B->prior = A;
C->prior = NULL;
LNode* p = H;
LNode* s = C;
bool isNotNull = linkedListIsNotNull(p);
if (isNotNull) {
insertElement(p, s);
traverseLinkedList(p);
printf("---------------------------\n");
LNode* q = deleteElement(s);
free(q);
traverseLinkedList(p);
}
else {
printf("链表为空!");
}
}
代码4: 在含头结点的双链表的第一个结点之前插入结点或者删除第一个结点.
可以看出, 在双链表里要删除一个结点, 我们只需要知道这个结点的地址信息即可, 因为其相邻的结点的地址信息已在该结点的内部储存.
2. 顺序表的插入删除
1. 顺序表的插入操作
图9. 顺序表插入元素
可插入下标位置p的取值范围是: 0到length;
当表长length等于数组长度maxSize的时候, 不可以再插入元素;
移动元素从后往前后移;
接下来写一个可以在顺序表中任一位置合法地插入一个新元素的函数. 所谓合法, ①插入元素的位置必须合法, 即0 <= p <= length; ②插入元素的时机必须合法, 即length < maxSize.
#include <iostream>
/// <summary>
/// 数组最大长度
/// </summary>
const int MAX_SIZE = 10;
/// <summary>
/// 顺序表插入元素
/// </summary>
/// <param name="arr">要操作的数组</param>
/// <param name="length">插入元素前的数组长度</param>
/// <param name="p">插入位置</param>
/// <param name="e">插入元素</param>
/// <returns></returns>
int insertElement(int* arr, int& length, int p, int e) {
if (p < 0 || p > length || length > MAX_SIZE) {
return 0; //不合法
}
for (int i = length - 1; i >= p; i--) //注意这里是i--
{
arr[i + 1] = arr[i];
}
arr[p] = e;
length++;
return 1;
}
int main()
{
int arr[MAX_SIZE] = { 1,2,3,4,5,6 };
int length = 6;
int result = insertElement(arr, length, 0, 9999);
if (result == 1) {
for (int i = 0; i < length; i++)
{
printf("%d\n", arr[i]);
}
}
}
代码5: 顺序表插入元素
2. 顺序表的删除操作
图10. 顺序表删除元素
注意, 若强行修改length的值, 如将length修改为3, 其它的不变, 则此时顺序表所存的线性表中的元素只有0, 1, 2中的元素, 其它的元素虽然也在数组中, 但是它们已经不属于该顺序表中的元素了. 0 ~ length - 1才是顺序表中的元素所在范围. 除此之外的都不算顺序表中的元素.
所以如果想将顺序表清零, 只需length = 0即可. 其它的不用管, 虽然那些元素还留在数组中, 但对于该顺序表来说, 它是不可见的.
可删除元素下标p的取值范围: 0 ~ length - 1;
当表长length等于0时, 不可以再删除元素;
移动元素从前往后前移;
#include <iostream>
/// <summary>
/// 数组最大长度
/// </summary>
const int MAX_SIZE = 10;
/// <summary>
/// 顺序表插入元素
/// </summary>
/// <param name="arr">要操作的数组</param>
/// <param name="length">插入元素前的数组长度</param>
/// <param name="p">插入位置</param>
/// <param name="e">插入元素</param>
/// <returns></returns>
int insertElement(int* arr, int& length, int p, int e) {
if (p < 0 || p > length || length > MAX_SIZE) {
return 0; //不合法
}
for (int i = length - 1; i >= p; i--) //注意这里是i--
{
arr[i + 1] = arr[i];
}
arr[p] = e;
length++;
return 1;
}
/// <summary>
/// 顺序表删除元素
/// </summary>
/// <param name="arr">要操作的数组</param>
/// <param name="length">数组删除元素前的长度</param>
/// <param name="p">要删除的位置</param>
/// <param name="e">要删除的元素</param>
/// <returns></returns>
int deleteElement(int* arr, int& length, int p, int& e) {
if (p < 0 || p > length - 1 || length <= 0) {
return 0;
}
e = arr[p];
for (int i = p; i < length - 1; i++)
{
arr[i] = arr[i + 1];
}
length--;
return 1;
}
int main()
{
int arr[MAX_SIZE] = { 1,2,3,4,5,6 };
int length = 6;
int e;
int result = deleteElement(arr, length, 0, e);
if (result == 1) {
printf("删除的元素: %d\n", e);
for (int i = 0; i < length; i++)
{
printf("%d\n", arr[i]);
}
}
}
代码6: 顺序表删除元素