单链表的初始化,整表创建,单个元素插入,单个元素删除,整表删除等操作

      很早之前学的数据结构,放了很久后,以致对里面的一些操作都有些遗忘,故而再次温习了一下数据结构,并整理了一点儿笔记,放在这里和大家分享, 我的代码注释的已经很详细了,对于容易出错的地方我也都有标注,欢迎大家交流。

#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("
");//换行
    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
", 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
", 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个元素的数据域并传值给*e
    printf("被取出的元素的值为:");
    printf("%d
", *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个节点之前插入元素15
    List_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
请按任意键继续. . .

原文地址:https://www.cnblogs.com/huster666/p/5642638.html