很早之前学的数据结构,放了很久后,以致对里面的一些操作都有些遗忘,故而再次温习了一下数据结构,并整理了一点儿笔记,放在这里和大家分享, 我的代码注释的已经很详细了,对于容易出错的地方我也都有标注,欢迎大家交流。
#include "stdafx.h" #include <stdio.h> #include <malloc.h> #include <stdlib.h> #include <time.h> #define OK 1 #define ERROR 0//#define typedef int Status;//函数返回的状态值类型 typedef int ElemType; typedef struct Node {ElemType data;struct Node *next; } Node;//定义一个单链表存储结构 typedef struct Node *LinkList;//定义一个线性表,定义的是Node结构体的指针//创建一个具有n个元素的单链线性表,采用头插法创建,注意:其中已经包含了初始化操作 //初始化链表,函数调用完毕后,L会指向一个空的链表,即会改变指针的值,所以要用*L //*L表示结构体指针的指针 Status List_Link_Create(LinkList *L,int n)//头插法 {LinkList p;*L =(LinkList) malloc(sizeof(Node));//产生一个头结点,并使得*L指向这个头结点,于是*L便是一个头指针,头指针是链表的必要元素if (L == NULL)return ERROR;(*L)->next = NULL;//使得头指针指向的内容为空,建立一个带头结点的单链表printf("请输出n个随机生成的数字:");for (int i = 0; i < n; i++){p = (LinkList)malloc(sizeof(Node));//生成新节点p->data = rand() % 100 + 1;//随机生成100以内的数字printf("%d", p->data);printf(" ");//字符与字符之间空格 p->next = (*L)->next;(*L)->next = p;//插入到表头 }printf("\n");//换行return OK; }Status List_Link_Length(LinkList L)//求出单链表的长度 {int j = 0;LinkList p;p = L;while (p != NULL){p = p->next;j++;}printf("单链表当前的长度=%d",j);return j; } //Status List_Link_Ini(LinkList L)//初始化一个线性单链表 //{ // L = (LinkList)malloc(sizeof(Node));//产生一个头结点,并使得L指向这个头结点,于是L便是一个头指针,头指针是链表的必要元素 // if (L == NULL) // return ERROR; // L->next = NULL;//使得头结点的指针域为空 // return OK; //}//销毁链表L,释放链表L申请的内存,使L的值重新变为NULL,所以会改变L的值,得用*L Status List_Link_Destory(LinkList *L) {LinkList p,q;p = (*L)->next;while (p){q = p->next;free(p);p = q;}(*L)->next = NULL;//头节点的指针域为空return OK; }Status List_Link_Insert(LinkList *L, int i, ElemType e)//在L中第i个元素之前插入新的数据元素e {int j;LinkList p, s;p = *L;j = 1;while (p&&j<i)//遍历寻找第i个节点 {p = p->next;++j;}if (!p || j > i)return ERROR;//第i个元素不存在s = (LinkList)malloc(sizeof(Node));//生成一个新节点s->data = e;s->next = p->next;//将p的后继节点赋值给s的后继p->next = s;printf("插入节点的元素的值为:%d\n", e);return OK;//插入成功 }//删除L的第i个数据元素,并用e返回其值 //注意这里是*e,而不是e,区别于插入当中的变量e Status List_Link_Delete(LinkList *L, int i, ElemType *e) {int j=1;LinkList p, q;p = *L;while (p->next&&j<i)//遍历寻找第i个元素 {p = p->next;++j;}if (!(p->next) || j > i)return ERROR;//第i个元素不存在 q = p->next;//q表示即将被删除元素的节点*e = q->data;p->next = q->next;//将q 后继赋值给p的后继free(q);//q被利用完毕后,将q释放printf("删除第%d个节点的元素值为:%d\n", i, *e);return OK;}Status List_Link_GetElem(LinkList L, int i, ElemType *e)//取出单链表L中的第i个元素,并通过*e返回 {int j;LinkList p;p = L->next;//找到单链表L中第一个节点j = 1;while (p&&j < i){p = p->next;++j;}if (!p || j > i)return ERROR;//第i个元素不存在*e = p->data;//取出第i个元素的数据域并传值给*eprintf("被取出的元素的值为:");printf("%d\n", *e);return OK; } int main()//测试函数 {LinkList L1;ElemType f,h;List_Link_Create(&L1, 6);List_Link_GetElem(L1, 3, &f);List_Link_Insert(&L1, 3, 15);//在链表的第3个节点之前插入元素15List_Link_Delete(&L1, 3, &h);//删除链表的第3个节点的元素,并返回给h输出return OK; }/*1.对于LinkList L : L是指向定义的node结构体的指针, 可以用->运算符来访问结构体成员, 即L->elem, 而(*L)就是个Node型的结构体了, 可以用点运算符访问该结构体成员, 即(*L).elem;2.对于LinkList *L:L是指向定义的Node结构体指针的指针, 所以(*L)是指向Node结构体的指针, 可以用->运算符来访问结构体成员, 即(*L)->elem, 当然, (**L)就是Node型结构体了, 所以可以用点运算符来访问结构体成员, 即(**L).elem;3.在链表操作中, 我们常常要用链表变量作物函数的参数, 这时, 用LinkList L还是LinkList *L就很值得考虑深究了, 一个用不好, 函数就会出现逻辑错误, 其准则是:如果函数会改变指针L的值, 而你希望函数结束调用后保存L的值, 那你就要用LinkList *L, 这样, 向函数传递的就是指针的地址, 结束调用后, 自然就可以去改变指针的值;而如果函数只会修改指针所指向的内容, 而不会更改指针的值, 那么用LinkList L就行了;*/
下面是我在vs2013中的测试结果:
请输出n个随机生成的数字:42 68 35 1 70 25
被取出的元素的值为:1
插入节点的元素的值为:15
删除第3个节点的元素值为:15
请按任意键继续. . .