链表的基本使用

说明:代码可能会有错误,如果有错误,请联系我改正,感谢。

#include <stdio.h>
#include <stdlib.h>
#define ElemType char
#define ERROR 0
#define OK 1
/*在进行链表操作时候需要注意该链表是否带有头节点,这里讨论的均是带有头结点的链表,头结点为空*/

/*链表的定义*/
/*此处是接触数据结构起点较难的一部分,逐步理解就是自定义数据类型Node来表示链表,而*LinkList这样的定义是为了区分头结点与其他节点
 * 含义上来讲Node * p的定义与LinkList L的定义都是一样的意思,一个链表的结点,但是更多时候L用来表示头结点*/
typedef struct Node{
    ElemType data;//数据域
    struct Node *next;//指向下一结点的指针
}Node, *LinkList;

/*链表的初始化*/
/*与链表的定义一样,*L表示头结点变量,而L则表示头结点指针,此处一定要仔细理解*/
void init_LinkList(LinkList *L){//这里*L实际意义并不是指针,而是指针指向的那一块地址的变量
    *L = (struct Node *)malloc(sizeof (struct Node ));//申请结点空间
    (*L)->next = NULL;//弄为空表
}

/*头插法建立单链表*/
void CreateLFromhead(LinkList L){//传递指针代表需要改变实参的量
    ElemType e;
    Node *p;//定义结点p来帮助建立链表
    int flag = 1;//循环判断变量
    while (flag){
        e = getchar();
        if(e != '$'){//如果没有接收到终止符号,则开始建立链表
            p = (struct Node *)malloc(sizeof (struct Node *));//为结点分配内存空间
            p->data = e;//给分配内存的结点数据域赋值
            p->next = L->next;
            L->next = p;
        } else{
            flag = 0;//终止循环
        }//此处$为终止符号,可随自己喜好更改
    }
}

/*尾插法建立单链表*/
void CreateFromtail(LinkList L){//同样的这里创建链表,需要传入头结点指针
    ElemType e;
    Node *p, *s;//这里需要两个结点来辅助实现需求
    int flag = 1;//循环判断变量
    p = L;//p一开始是头结点,后来不停往后移动
    while(flag){
        e = getchar();
        if(e != '$'){
            s = (struct Node *)malloc(sizeof (struct Node *));//为结点申请内存空间
            s->data = e;//为结点数据域赋值
            p->next = s;//将p结点指向s接待你
            p = s;//将p结点后移覆盖s结点
        } else{
            flag = 0;
            p->next = NULL;//当链表建立完毕,尾结点的指针为空
        }
    }
}

/*单链表按序号查找*/
/*因为链表并非顺序表是顺序存储的,链表是依靠指针指向地址,所以函数的类型是Node *类型的,这样才能得到返回的地址*/
Node * GetLocate(LinkList L, int i){//得到需要查找结点的地址(按序号查找)
    Node *p;
    int j;//用来判断链表中结点数
    p = L;
    j = 0;
    while(p->next != NULL && j < i){
        p = p->next;
        j++;
    }/*此处L->next != NULL 不难理解 但是 j < i相对绕,i表示的是需要查找结点的位置,
        j表示从0开始扫描过的结点数,当j==i时,则表示链表扫描到指定的结点,终止循环*/
    if(i == j){
        return p;
    } else{
        return NULL;
    }
}

Node * Locate(LinkList L, ElemType e){//得到需要查找的值的地址(按值查找)
    Node *p;
    p = L->next;//这里可能有p=L 的写法因为头结点为空,所以两种写法都对,但是如果写第二种while循环需要修改为p->next!=NULL
    while (p!= NULL && p->data != 'e'){
        p = p->next;
    }//扫描链表直至表位或者当前结点数值就是我们要查找的数据
    if(p->data == e){//判断是哪一种情况
        return p;
    } else{
        return NULL;
    }
}

/*求单链表的长度*/
int ListLength(LinkList L){
    int i;//用来表示单链表的长度
    Node *p;//创建结点来辅助计算
    p = L->next;//这里有的写法是p=L,如果那么写,考虑到头节点为空,while循环内变量需要改变为p->next!=NULL
    i = 0;
    while(p != NULL)
    {
        p = p->next;//循环下一指针
        i++;
    }
    return i;//返回单链表的长度
}

/*单链表的插入*/
int Insert(LinkList L, int i, ElemType e){
    int j;
    Node *p, *s;//p来辅助操作,s用来表示新节点
    j = 0;
    p = L;
    while(p->next != NULL && j < i - 1){//此处原理之前已经介绍过
        p = p->next;
        j++;
    }
    if(p == NULL){
        printf("The locate not true");
        return ERROR;
    }//这里!p是因为如果p是空的则表达式是正确的,而如果p为空则表示i不再链表区间内
    /*上述情况都不存在,则表示位置在链表区间内,可以进行操作。*/
    s = (struct Node *)malloc(sizeof (struct Node *));
    s->data = e;
    s->next = p->next;
    p ->next = s;
    return OK;
}

/*单链表的删除*/
int Deletebylocate(LinkList L, int i){//删除某个节点{
    Node *p, *s;
    int j;
    j = 0;
    p = L;
    while(p->next != NULL && j < i-1){
        p = p->next;
        j++;
    }
    if(p->next == NULL){
        printf("The locate not true");
        return ERROR;
    }//与插入思考差不多
    s = p->next;
    p->next = p->next->next;
    free(s);
}

void  Deletebydata(LinkList L, ElemType e){//删除某个元素在链表中的第一个节点
    Node *p, *s;
    int i;
    i = 0;
    p = L;
    while(p->next != NULL){
        i++;
        if(p->data == e){
            Deletebylocate(L,i);//调用已经建立好的删除点的函数
            break;
        }else{
            p = p->next;
        }
    }
}

/*单链表的输出*/
void OutputLinkList(LinkList L){
    while(L->next != NULL){
        printf("%c", L->data);
        L = L->next;
    }
}

int main() {//主函数,如果需要测试什么功能,则可以自己加入
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值