含表头的链表ADT(C语言版)

来源:互联网 发布:pgdump 创建数据库 编辑:程序博客网 时间:2024/06/05 16:09

表头L为指针,指向一个结构体,L->next表示L指向的结构体中的结构的next域,这个next存储的是链表第一个节点的地址,所以L->next表示链表第一个节点的地址,所以L->next->element表示链表第一个节点element域中的值。

当表头L(指针)作为自定义函数参数传入时,L是作为一个临时变量存在的,所以对L进行的操作,并不改变表头的地址本身。但是当L->next作为左值出现时,却会改变L->next的值。所以,当表头L(指针)作为自定义函数参数传入时,函数只创建指针L的临时变量,而不创建结构体临时变量。编写代码时,当L->next作为左值出现时,应注意L->next的值被改变是否是有意为之。

测试代码代码如下:

<span style="font-size:12px;">#include <stdio.h>#include <malloc.h>struct Test;typedef Test * Node;struct Test{int num;Node next;};int main(){Node A, B;A = (Node)malloc(sizeof(struct Test));B = (Node)malloc(sizeof(struct Test));void F(Node L, Node M);A -> next = NULL;A -> num = 1;B -> next = A;B -> num = 2;printf("A's add is%p\nA->next is%p\n", A, A -> next);F(A, B);}void F(Node L, Node M){L -> next = M -> next;L = M;printf("L's add is%p\nL->next is%p\n", L, L -> next);}//输出值表明A L L->next 表示同一地址 均为A地址,A->next为NULL </span>

链表ADT代码头文件:

#ifndef MYLIST_H_#define MYLIST_H_#pragma warning(disable:4996)#include <stdbool.h>#define OVERFLOW -1 //溢出时调用exit返回-1 #define LIST_IS_EMPTY -2struct MyListNode;typedef struct MyListNode * Node; //指向节点的指针 typedef struct MyListNode * List; //指向表头的指针 typedef int ElemType;/*以下为接口函数声明*/bool IsEmpty(List L); //输入表头,表为空输出trueList InitList(void); //输入表头,为其开辟内存,初始化一个空表Node NewNode(ElemType E);//输入E,新建数据域为E的节点,返回节点地址List DestroyList(List L);//销毁表,释放空间void ClearList(List L);//清空表,仅留表头,其他空间释放void AddFront(List L, Node N, ElemType E);//为表L的节点N增加前驱,数据域为Evoid AddRear(List L, Node N, ElemType E);//增加后继void AddTail(List L, ElemType E);//在表尾增加数据域为E的节点 void DeleteElem(List L, ElemType E);//删除表L中数据域与E值相同的节点 int ListLength(List L);//返回表中节点数,表头不计在内void LinkList(List L1, List L2);//将表L2接在L1后面void PrintList(List L);//顺序输出表中数据 #endif

实现代码:

#include <stdlib.h>#include <stdio.h>#include <malloc.h>#include "MyList.h" struct MyListNode{ElemType element;Node next; //指向下一个节点的指针};bool IsEmpty(List L){return L->next == NULL;}Node NewNode(ElemType E){Node N;N = (Node)malloc(sizeof(struct MyListNode));if (N == NULL)exit(OVERFLOW);N->next = NULL;N->element = E;return N;}List InitList(void){List L;L = (List)malloc(sizeof(struct MyListNode));if (L == NULL)exit(OVERFLOW);L->next = NULL;return L;}/*void InitList(List L) //相比于上面那一种写法,哪一种更好{L = (List)malloc(sizeof(struct MyListNode));if(L == NULL)exit(OVERFLOW);L->next = NULL;}*/List DestroyList(List L){Node tempN;while (L != NULL){tempN = L->next;free(L);L = tempN;}return NULL; //防止表头成为野指针}void ClearList(List L)//表头指向的内存不被释放{Node tempN;L = L->next;while (L != NULL){tempN = L->next;free(L);L = tempN;}}void AddFront(List L, Node N, ElemType E){Node frontN = NewNode(E);while (L->next != N)L = L->next;frontN->next = L->next;L->next = frontN;}void AddRear(List L, Node N, ElemType E){Node RearN = NewNode(E);RearN->next = N->next;N->next = RearN;}void AddTail(List L, ElemType E){while (L->next != NULL)L = L->next;L->next = NewNode(E);}//DeleteElem算法,遍历链表,遇到符合条件的节点,让其前驱指向其后继,free当前节点,L指向后继,继续遍历void DeleteElem(List L, ElemType E){//L为遍历指针,frontN为L的前驱指针,tempN为临时存储L后继的指针,配合free使用Node tempN, frontN = L;L = L->next;//排除头结点干扰while (L != NULL){if (L->element == E){tempN = L->next;free(L);L = tempN;frontN->next = tempN;}else{frontN = L;L = L->next;}}}int ListLength(List L){int sum = 0;L = L->next; //从第一个节点开始数,除去表头干扰while (L != NULL){sum++;L = L->next;}return sum;}void LinkList(List L1, List L2){while (L1->next != NULL)L1 = L1->next;L1->next = L2->next;free(L2);//删除表L2表头 L2 = NULL;//防止L2表头变为野指针 }void PrintList(List L){if (IsEmpty(L))exit(LIST_IS_EMPTY);//L为空则报错 L = L->next;//头结点element域为空,所以从第一个节点开始输出 while (L != NULL){printf("%d ", L->element);L = L->next;}printf("\n");}

测试代码:

#include <stdio.h>#include <stdlib.h>#include "MyList.h"int main(){List L1, L2;int length1, length2, e, i;//length1表示L1节点总数,e用于临时存储element键入值 L1 = InitList();//初始化链表 L2 = InitList();printf("输入第一个表中的总节点数:");scanf("%d", &length1);printf("输入%d个节点的element值:", length1);for (i = 0; i < length1; i++){scanf("%d", &e);AddTail(L1, e);}printf("输入第二个表中的总节点数:");scanf("%d", &length2);printf("输入%d个节点的element值:", length2);for (i = 0; i < length2; i++){scanf("%d", &e);AddTail(L2, e);}printf("表L1为:");PrintList(L1);printf("表L2为:");PrintList(L2);DeleteElem(L1, 3);printf("执行删除3操作后的表L1为:");PrintList(L1);LinkList(L1, L2);length1 = ListLength(L1);printf("合并后的表L1长为:%d\n", length1);printf("合并后的表L1为:");PrintList(L1);system("pause");}



0 0