前言
基本上搞定了顺序表和单链表就能对指针了然于心了,下面是我自己调通的单链表基本操作和执行代码,仅用作记录。
单链表基本操作代码
- 代码包括以下单链表基本操作:
- 初始化头指针
- 单链表判空
- 尾插法建立单链表
- 头插法建立单链表
- 插入新结点
- 删除已有结点
- 顺序打印单链表所有结点数据域
下面附完整代码,使用Visual Studio2019,我这边确保调通了(如果没通,可能与安全函数有关,请尝试去vs设置里打开安全检查)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#define ERROR 0
#define OK 1
typedef int Elemtype;
typedef int Status;
/*
使用typedef定义一个结构体变量,并将其命名为LNode;
为了方便,可以同时命名一个结构体指针变量*Linklist,等价与 struct Node* Linklist;
在后续函数传参中,Linklist结构体指针变量专用于指代头指针,而LNode结构体变量专用于指代链表元素;
*/
/*补充1:结构体自引用与链表
1. 链表在物理结构上是离散的,所以为了在逻辑上连续,需要在定义时利用结构体自引用特性构造一个指针域指向后继结点;
2. 引用自身时需要利用指针的特性建立,因为指针的占用大小在系统中是有定义的,如代码段中的定义就是最正确的方式之一;
3. 切记不可直接使用非指针变量自引用,这是因为在定义是,结构体本身还未初始化,未初始化变量引用未初始化变量会导致内存溢出,所以是非法的;
// 一种典型的错误定义方式如下
// typedef struct Node{
// Elemtype data;
// struct Node next;
// }LNode,*Linklist;
*/
typedef struct Node {
Elemtype data;
struct Node* next;
}LNode, * Linklist;
/*
定义一个函数,用于初始化头指针;
由于传入指针变量本身也需要被修改,所以要进行函数的地址传递,即传递一个Linklist结构体指针变量的地址(否则会出现“L=nullptr”的报错);
/
/这里做一个详细说明;
/已知有一个结构体指针L,其中L->data表述L指向结构体的数据域,L->next表述L指向结构体的指针域;
/
*/
Status initLHead(Linklist& L) {
L = (Linklist)malloc(sizeof(LNode));
L->next = NULL;
return OK;
}
/*
判空操作不需要对链表进行修改,所以进行函数的值传递;
*/
Status isEmpty(Linklist L) {
if (L->next == NULL) {
printf_s("链表为空");
return ERROR;
}
return OK;
}
/*
由用户输入数值对单链表进行初始化,使用尾插法
*/
Status tailInitList(Linklist& L, int num) {
Linklist p;//功能指针,从头指针开始顺序移动,指向每个结点
Linklist s;//用于动态创建新的结点空间
int tempData;//用于每次给新结点赋值
p = L;
if (p->next != NULL) {
printf_s("当前链表不需要初始化,将继续执行下一步或选择执行其它操作。\n");
return ERROR;
}
else if (num <= 0) {
printf_s("插入元素个数为非法值,尾插建表失败\n");
return ERROR;
}
while (num != 0) {
s = (Linklist)malloc(sizeof(LNode));
scanf_s("%d", &tempData);
s->data = tempData;
if (p != NULL) {//!!!!注意,指针一定要结合非NULL判断进行,否则会产生C6011报错或者告警
p->next = s;
p = s;
p->next = NULL;
num--;
}
}
return OK;
}
/*
由用户输入数值对单链表进行初始化,使用头插法
*/
Status headInitList(Linklist& L, int num) {
Linklist p = L;//功能指针
Linklist s = NULL;//新建结点指针
int tempData = 0;
if (p == NULL) {
printf_s("头指针非法或为nullptr,请重新初始化头指针。\n");
return ERROR;
}
else if (p->next != NULL) {
printf_s("该链表不需要初始化。\n");
return ERROR;
}
else if (num <= 0) {
printf_s("输入的插入元素个数为非法值,尾插建表失败。\n");
}
while (num != 0) {
s = (Linklist)malloc(sizeof(LNode));
scanf_s("%d", &tempData);
s->data = tempData;
if (p != NULL) {
s->next = p->next;
p->next = s;
num--;
}
}
return OK;
}
/*
打印单链表所有元素
*/
Status printCheck(Linklist L) {
Linklist p = L;
if (p->next == NULL) {
printf_s("没有元素可以打印。\n");
return ERROR;
}
printf_s("当前链表为:");
while (p->next != NULL) {//注意此处,由于初始时p=L,所以要检查p->next是否为NULL,否则将溢出
p = p->next;//由于最开始p=L,所以要先将p指向下一个有意义结点,也就是p->next
printf_s("%d ", p->data);//while循环里这两句不要反过来
}
printf_s("\n");
return OK;
}
/*
插入函数,在pos位置插入一个数据域为e的结点的功能函数
*/
Status insertList(Linklist& L, Elemtype e, Elemtype pos) {
int i = 1;
Linklist p = L;
Linklist s = NULL;
if (p == NULL || pos <= 0) {
printf_s("函数传值有非法数值,即将结束程序。\n");
return ERROR;
}
while (p != NULL && i < pos) {
p = p->next;
i++;
}
if (p == NULL) {
return ERROR;
}
s = (Linklist)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
/*
删结点函数,删除第pos个结点,用全局变量elem获取被删除结点的数值
*/
Status deleteList(Linklist& L, int pos, int& elem) {
Linklist s;//功能指针1
Linklist p = L;//功能指针2
int i = 1;//计数器
if (p == NULL) {
printf_s("单链表错误,即将结束程序。\n");
return ERROR;
}
while (p != NULL && i < pos) {
p = p->next;
i++;
}
if (p->next == NULL) {
printf_s("结点位置过大,即将结束程序。\n");
return ERROR;
}
s = p->next;
elem = s->data;
p->next = s->next;
free(s);
printf_s("删除成功,即将结束程序。\n");
return OK;
}
int main() {
Linklist L = NULL;
Linklist M = NULL;
Elemtype pos = 0;
Elemtype dpos = 0;
Elemtype e = 0;
Elemtype num = 0;
Elemtype elem = 0;
initLHead(L);
isEmpty(L);
printf_s("准备初始化链表,请输入你想插入的元素个数(尾插法):");
scanf_s("%d", &num);
tailInitList(L, num);
printCheck(L);
printf_s("请输入想插入元素的数值:");
scanf_s("%d", &e);
printf_s("请输入想插入元素的位置:");
scanf_s("%d", &pos);
insertList(L, e, pos);
printCheck(L);
printf_s("请输入想删除元素的位置:");
scanf_s("%d", &dpos);
deleteList(L, dpos, elem);
printCheck(L);
/*
initLHead(M);
isEmpty(M);
printf_s("准备初始化链表,请输入你想插入的元素个数(头插法):");
scanf_s("%d", &num);
headInitList(M, num);
printCheck(M);
*/
}