文章目录

  • ​​不带头节点​​
  • ​​带头节点​​

不带头节点

// 插入(按位序插入)(在前驱节点后插入)
bool ListInsert(LinkList &L, int i, ElemType e) {
LNode *s, *p;
int j = 1;
if (i < 1)
return false;
if (L == NULL)
return false;
if (i == 1) { // 因为首节点无前驱(即头节点),所以需要特殊处理
s = (LNode *) malloc(sizeof(LNode));
s->next = L->next;
L = s;
return true;
}
p = L; // p指针指向首节点
while (p != NULL && j < i - 1) { // 寻找待插入节点的前驱
p = p->next;
j++;
}
if (p == NULL)
return false;
s = (LNode *) malloc(sizeof(LNode));
if (s == NULL)
return false; // 申请空间失败
s->next = p->next;
s->data = e;
p->next = s;
return true;
}


// 删除(按位序删除)
bool ListDel(LinkList &L, int i, ElemType &e) {
LNode *p, *q;
int j = 1;
if (i < 1)
return false; // 删除位置不合法
if (L == NULL) // 表为空表
return false;
if (i == 1) { // 因为首节点无前驱(即头节点),所以需要特殊处理
e = L->data;
q = L->next;
L = q;
return true;
}
p = L; // p指针指向首节点
while (p != NULL && j < i - 1) { // 寻找待删除节点的前驱
p = p->next;
j++;
}
// p == NULL || p->next == NULL 顺序不能颠倒
// 删除位置分别考虑>=length+1,=length
if (p == NULL || p->next == NULL)
return false;
q = p->next;
e = q->data;
p->next = q->next;
free(q);
return true;
}

带头节点

代码编写

#include <stdio.h>
#include <Windows.h>

#define ElemType int

// 定义单链表
typedef struct LNode {
ElemType data;
struct LNode *next;
} LNode, *LinkList;

// 采用头插法建立单链表
void CreateListF(LinkList &L, ElemType a[], int n) {
LNode *s;
int i;
L = (LNode *) malloc(sizeof(LNode)); // 创建头节点
L->next = NULL; // 头节点的next域置为NULL
for (i = 0; i < n; i++) {
s = (LNode *) malloc(sizeof(LNode)); // 创建新节点s
s->data = a[i];
s->next = L->next;
L->next = s;
}
}

/*头插法建立单链表虽然简单,但生成的链表中的节点的次序和元素组中节点的次序刚好相反。
* 若希望顺序一致,可采用尾插法建立单链表。方法是增加一个尾节点指针r,始终指向当前
* 链表的尾节点*/
// 采用尾插法建立单链表
void CreateListR(LinkList &L, ElemType a[], int n) {
LNode *s, *r;
int i;
L = (LNode *) malloc(sizeof(LNode)); // 创建头节点
r = L; // r始终指向尾节点,开始时指向头节点
for (i = 0; i < n; i++) {
s = (LNode *) malloc(sizeof(LNode));
s->data = a[i];
r->next = s;
r = s;
}
r->next = NULL; // 尾节点next域置为空
}

// 查找(按值查找)若找到,返回位序,否则返回0
int LocateElem(LinkList L, ElemType e) {
int i = 1;
LNode *p = L->next; // p指针指向首节点
while (p != NULL && p->data != e) { // 从第1个结点开始查找data域为e的结点
p = p->next;
i++;
}
if (p == NULL) return 0;
else return i;
}

// 查找(按序号查找)若找到,返回节点指针,否则,返回NULL
LNode *GetElem(LinkList L, int i) {
int j = 0; // 控制当前p指向第几个结点
LNode *p;
if (i < 0)
return NULL;
p = L; // L指向头结点,头结点是第0个结点(不存数据)
while (p != NULL && j < i) {
p = p->next;
j++;
}
return p;
}

// 在指定节点后插入(即在待插入节点的前驱节点后插入)
// 插入元素的范围[1,length + 1]这个闭区间,其它位置不合法
bool InsertNextNode(LNode *p, ElemType e) {
LNode *s;
if (p == NULL)
return false;
s = (LNode *) malloc(sizeof(LNode));
if (s == NULL)
return false; // 申请空间失败
s->data = e;
s->next = p->next;
p->next = s;
return true;
}

// 插入(按位序插入)(在前驱节点后插入)
bool ListInsert(LinkList &L, int i, ElemType e) {
LNode *p;
if (i < 1)
return false; // 插入位置不合法
p = GetElem(L, i - 1); // 寻找前驱节点
return InsertNextNode(p, e);
}


/*// 上述代码封装了,这个是一个函数干到底
// 插入(按位序插入)(在前驱节点后插入)
bool ListInsert(LinkList &L, int i, ElemType e) {
LNode *p, *q, *s;
int j = 0;
if (i < 1)
return false; // 插入位置不合法
p = L; // L指向头结点,头结点是第0个结点(不存数据)
while (p != NULL && j < i -1 ) { // 寻找前驱节点
p = p->next;
j++;
}
if (p == NULL)
return false; // 不仅可以判断插入位置不合法,而且可以判断表为空
s = (LNode *) malloc(sizeof(LNode));
if (s == NULL)
return false; // 申请空间失败
s->data = e;
s->next = p->next;
p->next = s;
return true;
}*/

/*// 在指定节点前插入
// 插入元素的范围[1,length]这个闭区间,其它位置不合法
bool InsertPriorNode(LNode *p, ElemType e) {
LNode *s;
if (p == NULL)
return false;
s = (LNode *) malloc(sizeof(LNode));
if (s == NULL)
return false; // 申请空间失败
s->next = p->next;
p->next = s;
s->data = p->data;
p->data = e;
return true;
}

// 插入(按位序插入)
bool ListInsert(LinkList &L, int i, ElemType e) {
LNode *p;
if (i < 1)
return false; // 插入位置不合法
p = GetElem(L, i); // 寻找插入节点
return InsertPriorNode(p, e);
}
// 表面上是在待插入节点前插入,实则是在待插入节点后插入
*/

// 删除(按位序删除)
bool ListDel(LinkList &L, int i, ElemType &e) {
LNode *p, *q;
if (i < 1)
return false; // 删除位置不合法
p = GetElem(L, i - 1); // 寻找前驱节点
// 1、如果删除位置为 length + 1 或者 > length + 1,抛异常
// 2、p == NULL || p->next == NULL 位置不能互换成 p->next == NULL || p == NULL
if (p == NULL || p->next == NULL)
return false;
q = p->next;
e = q->data; // 用e将被删除元素值带回
p->next = q->next;
free(q);
return true;
}

/*// 上述代码封装了,这个是一个函数干到底
// 删除(按位序删除)
bool ListDel(LinkList &L, int i, ElemType &e) {
LNode *p, *q, *s;
int j = 0;
if (i < 1)
return false; // 删除位置不合法
p = L; // L指向头结点,头结点是第0个结点(不存数据)
while (p != NULL && j < i -1 ) { // 寻找前驱节点
p = p->next;
j++;
}
// 1、如果删除位置为 length + 1 或 > length + 1,抛异常
// 2、p == NULL || p->next == NULL 位置不能互换成 p->next == NULL || p == NULL
if (p == NULL || p->next == NULL)
return false; // 不仅可以判断删除位置不合法,而且可以判断表为空
q = p->next;
e = q->data; // 用e将被删除元素值带回
p->next = q->next;
free(q);
return true;
}*/

// 单链表的遍历
void Display(LinkList L) {
LNode *p;
p = L->next; // 指向首节点
printf("当前顺序表元素为: ");
while (p != NULL) {
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}

int main() {
int a[] = {1, 2, 3, 4, 7};
int m, n;
LNode *e;
LinkList L; // 声明一个单链表
// CreateListF(L, a, 5); // 头插法建立单链表
CreateListR(L, a, 5); // 尾插法建立单链表
Display(L);
e = GetElem(L, 5); // 查找(按序号查找)
if (e == NULL)
printf("%s\n", "没有该元素!");
else
printf("元素为:%d\n", e->data);
m = LocateElem(L, 3); // 查找(按值查找)
printf("3的位置为:%d \n", m);
ListInsert(L, 6, 8); // 插入(按位序插入)
Display(L);
ListDel(L, 1, n); // 删除(按位序删除)
Display(L);
// system("pause");
return 0;
}

运行结果

2.3.2单链表基本操作(不带头节点&带头节点)_头结点