问题描述:
结构体定义结构体指针变量"L"即一个结点,“L”指向第一个结点首地址。定义一个创建函数来创 建链表。而使用“L”时,需要将“L”初始化,即将“L”传入创建函数之前需要初始化“L”,或者直接调用 “L”的地址即“&L”。
下方采用的就是第二种方式,功能函数采用“双重指针”(ListL或struct LinkList**L)定义形参来接收传入函数的“L”的地址,然后再进行其他操作。这种方式避免了“L”的初始化。(typedef struct LinkList List)
第二种方式函数收到的时“L”的地址,以*M的形式就可以定位到“L”,然后进行开辟空间来开辟新结点。而第一种方式,初始化“L”后,可直接传“L”,L为头结点首地址,也为地址,而且是main函数种所声明的,所以函数结束也不会释放空间(并不在函数中开辟的空间)。
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
struct LinkList {
ElemType data;
struct LinkList* next;
};
typedef struct LinkList* List;
#define LZN sizeof(struct LinkList)
#define ERROR 0
//创建链表
void create_List(List* M, int n) {//注意这里的struct LinkList**M(List*M)千万别写成struct LinkList*M
struct LinkList* p; //因为需要对L开辟空间,L里存储的是结构体变量首地址,而传过来的是L的地址
*M = (List)malloc(LZN); //需要再来一重指针接收L地址,以*M引用L内的内容,List*M形式比较容易区分
(*M)->data = n;
(*M)->next = NULL;
for (int i = 1;i <= n;i++) {
p = (List)malloc(LZN);
p->data = i;
p->next = (*M)->next;
(*M)->next = p;
}
}
//插入元素
void ListInsert(List* L, int i, ElemType e) {
struct LinkList* p,* q;
int j = 1;
p = (*L);
while (p&&j<i) {
p = p->next;
++j;
}
if (!p||j>i) {
return ERROR;
}
q = (List)malloc(LZN);
q->data = e;
q->next = p->next;
p->next = q;
}
//删除元素
void ListDelete(List* M, int i,ElemType*e) {
struct LinkList* p;
struct LinkList* q;
int j = 1;
p = *M;
while (p&&j<i) {
p = p->next;
j++;
}
if (!p||j>i) {
return ERROR;
}
q = p->next;
*e = q->data;
p->next = q->next;
free(q);
}
//整表删除
void ClearList(List*M) {
struct LinkList* p;
struct LinkList* q;
p = (*M)->next;
while (p) {
q = p->next;
free(p);
p = q;
}
(*M)->next = NULL;
}
void main() {
struct LinkList* L;
struct LinkList* p;
int e;
//int m;
//e = &m;
ElemType n;
n = 5;
//创建部分测试
void create_List(List* L, int n);
create_List(&L,n);
p = L; //将L首地址赋给p,对p初始化
printf("创建链表\n");
for (int i = 0;i <= n;i++) {
printf("%d ",p->data);
p = p->next;
} //循环结束,p指向最末尾
printf("\n");
//插入部分测试
p = L; //重新将L首地址赋给p,为后面循环准备
void ListInsert(List* L, int i, ElemType e);
ListInsert(&L, 3, 12);
printf("链表插入\n");
for (int i = 0;i <= n+1;i++) {
printf("%d ", p->data);
p = p->next;
}
printf("\n");
//删除部分测试
p = L;
void ListDelete(List * M, int i, ElemType * e);
ListDelete(&L, 3, &e); //取e的地址,用于ListDelete函数接收,再向这个地址赋值,即为e的值
printf("删除元素\n");
for (int i = 0;i <= n ;i++) {
printf("%d ", p->data);
p = p->next;
}
printf("\n");
printf("删除的元素:%d\n",e);
//整表删除测试
void ClearList(List * M);
ClearList(&L);
p = L;
printf("整表删除\n");
while(p) {
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
下方为第一种方式,(只编写了“创建”、“插入”功能函数)定义“L”之后,对“L”进行初始化,分配了一个结点空间,创建了头结点,然后将初始化之后的“L”传入功能函数,再完成后续操作。功能函数定义了结构体指针变量(单指针struct LinkList*L)来接收传入的“L”,对于带有头结点的链表比较友好。
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
struct LinkList {
ElemType data;
struct LinkList* next;
};
#define LZN sizeof(struct LinkList)
#define ERROR 0
//创建链表
void create_List(struct LinkList* M, int n) {
struct LinkList* p;
for (int i = 1;i <= n;i++) {
p = (struct LinkList*)malloc(LZN);
p->data = i;
p->next = M->next;
M->next = p;
}
}
//插入元素
void ListInsert(struct LinkList* L, int i, ElemType e) {
struct LinkList* p, * q;
int j = 1;
p = L;
while (p && j < i) {
p = p->next;
++j;
}
if (!p || j > i) {
return ERROR;
}
q = (struct LinkList*)malloc(LZN);
q->data = e;
q->next = p->next;
p->next = q;
}
void main() {
struct LinkList* L;
struct LinkList* p;
int e;
ElemType n;
n = 5;
L = (struct LinkList*)malloc(LZN); //初始化"L",后续需要将L直接传入,而不是传L地址,故要先初始化。
L->data = n;
L->next = NULL;
//创建部分测试
void create_List(struct LinkList* L, int n);
create_List(L, n);
p = L; //将L首地址赋给p,对p初始化
printf("创建链表\n");
for (int i = 0;i <= n;i++) {
printf("%d ", p->data);
p = p->next;
} //循环结束,p指向最末尾
printf("\n");
//插入部分测试
void ListInsert(struct LinkList* L, int i, ElemType e);
ListInsert(L, 3, 12);
p = L; //将L首地址赋给p,对p初始化
printf("创建链表\n");
for (int i = 0;i <= n+1;i++) {
printf("%d ", p->data);
p = p->next;
} //循环结束,p指向最末尾
printf("\n");
}