【数据结构】——单链表

速通回忆

如果你之前学过链表,可以直接看我下面的这个项目,实现了下面专题中所有内容;

如果你是个新手建议先不要看下面这个项目,先好好看一下下面每一个部分的代码思路,并尝试自己去写一下

/* 
 * 功能:单链表操作 
 * 作者:此乃刘同学(www.liustu.com.cn)
 */
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

/* 创建学生信息结构体 */
typedef struct{
    char name[20];      /* 学生姓名 */
    int age;            /* 学生年龄 */
}stu_data;

/* 定义学生的单链表 */
typedef struct Node{
    stu_data data;
    struct Node *next; 
}stu_link,*Link_ponit;

/* 链表初始化 */
Link_ponit Link_Init(){
    Link_ponit link = (Link_ponit)malloc(sizeof(stu_link));        /* 动态分配存储空间 */
    link->next = NULL;          /* 设置链表指针指向空 */
    return link;
}   

/* 
 * 链表创建头插法 
 * 思路:动态分配一个新的空间,存放数据后;把当前链表的next指向stu的next,再修改stu的next指向新链表
 */
void LinkCreateH(Link_ponit p){
    /* 动态分配存储空间 */
    Link_ponit n = (Link_ponit)malloc(sizeof(stu_link));
    Link_ponit stu = p;
    /* 读取信息 */
    printf("(头插法)请输入学生的姓名:");
    scanf("%s",n->data.name);
    printf("(头插法)请输入学生的年龄:");
    scanf("%d",&n->data.age);
    /* 将新节点放在链表头结点的下一个节点 */
    n->next = stu->next;
    stu->next = n;
}

/* 
 * 链表创建尾插法 
 * 思路:动态分配一个新的空间,存放数据后;把传来的链表指针,指向最后一个,把p的next指向最后一个的next最后一个next指向p
 */
void LinkCreateL(Link_ponit n){
    /* 动态分配存储空间 */
    Link_ponit p = (Link_ponit)malloc(sizeof(stu_link));
    Link_ponit stu = n;
    /* 读取信息 */
    printf("(尾插法)请输入学生的姓名:");
    scanf("%s",p->data.name);
    printf("(尾插法)请输入学生的年龄:");
    scanf("%d",&p->data.age);
    /* 将指针指向链表最后一个节点的位置 */
    while(stu->next != NULL) 
        stu = stu->next;
    /* 在链表末尾插入新节点 */
    stu->next = p;
    p->next = NULL;
}

/* 链表遍历输出 */
void LinkList_print(Link_ponit n){
    /* 创建一个新指针,指向链表的头节点 */
    Link_ponit stu = n;
    printf("|   学生姓名    |   学生年龄    |\n");
    /* while循环遍历 */
    while(stu->next != NULL){
        printf("|\t%s\t|\t%d\t|\n",stu->next->data.name,stu->next->data.age);
        stu = stu->next;
    }
}

/* 链表遍历修改某个节点的值 */
void LinkListReplace(Link_ponit n,char *stu_n){
    /* 创建一个新指针,指向链表的头节点 */
    Link_ponit stu = n;
    /* 编译查找与stu_n字符串相同的链表节点 */
    while(stu->data.name != NULL){
        if(strcmp(stu->data.name,stu_n)==0){
            /* 修改信息 */
            printf("请输入你要修改%s同学的年龄:",stu_n);
            scanf("%d",&(stu->data.age));
            break;
        }
        stu = stu->next;
    }
    /* 遍历到头也没有查到,则返回失败 */
    if(stu == NULL)
        printf("查询无此同学\n");
}

/* 在某个位置插入一个节点 */
void LinkList_Insert(Link_ponit n, int space){
    /* 创建一个新指针,指向链表的头节点 */
    Link_ponit stu = n;
    /* 将指针移动到对应位置 */
    for(int i=0; i<space; i++){
        stu = stu->next;
    }
    /* 如果移动次数太多,则超出链表的范围 */
    if(stu == NULL){
        printf("插入位置超出最大范围!\n");
        return ;
    }
    /* 分配一个节点的动态空间,存储要插入的数据 */
    Link_ponit p = (Link_ponit)malloc(sizeof(stu_link));
    printf("(插入操作)请输入学生的姓名:");
    scanf("%s",p->data.name);
    printf("(插入操作)请输入学生的年龄:");
    scanf("%d",&p->data.age);
    /* 修改链表指向新的节点 */
    p->next = stu->next;
    stu->next = p; 
}

/* 删除一个节点 */
void LinkList_Delete(Link_ponit n, char *stu_n){
    /* 创建一个新指针,指向链表的头节点 */
    Link_ponit stu = n;
    Link_ponit p = (Link_ponit)malloc(sizeof(stu_link));
    /* 遍历查找,查看与stu_n字符串相同的节点 */
    while(stu->next != NULL){
        if(strcmp(stu->next->data.name, stu_n) == 0){
            /* 替换要删除的节点 */
            p = stu->next;
            stu->next = p->next;
            /* 释放要删除的节点空间 */
            free(p);
            printf("删除成功\n");
            return;
        }
        stu = stu->next;
    }
    printf("查询无结果\n");
    free(stu);
}

int main()
{
    Link_ponit stu = Link_Init();       /* 创建一个链表 */
    LinkCreateH(stu);                   /* 用头插法插入一个接单 */
    LinkCreateL(stu);                   /* 用尾插法插入一个接单 */
    LinkList_print(stu);                /* 遍历输出所有节点信息 */
    LinkListReplace(stu, "stu");        /* 替换某个节点的信息 */
    LinkList_print(stu);                /* 遍历输出所有节点信息 */
    LinkList_Insert(stu,2);             /* 在某个位置插入一个节点 */
    LinkList_print(stu);                /* 遍历输出所有节点信息 */
    LinkList_Delete(stu, "demo");       /* 删除某个节点 */
    LinkList_print(stu);                /* 遍历输出所有节点信息 */

    free(stu);                          /* 释放动态分配内存 */
    return 0;
}

链表理论

链表的基本思维是,利用结构体的设置,额外开辟出一份内存空间去作指针,它总是指向下一个结点,一个个结点通过NEXT指针相互联系,串联

插入删除操作也就相当简单,只需要修改指针所指向的区域就可以了,不需要进行大量的数据移动操作

链表解决了数组不方便移动,插入,删除元素的弊端,但相应的,链表付出了更加大的内存牺牲换来的这些功能的实现

单链表设计

单链表的结点定义

//定义结点类型
typedef struct Node {
    int data;       //数据类型,你可以把int型的data换成任意数据类型,包括结构体struct等复合类型
    struct Node *next;          //单链表的指针域
} Node,*LinkedList;  
//Node表示结点的类型,LinkedList表示指向Node结点类型的指针类型

单链表的初始化

LinkedList listinit(){
    Node *L;
    L=(Node*)malloc(sizeof(Node));      //开辟空间 
    if(L==NULL){                     //判断是否开辟空间失败,这一步很有必要
        printf("申请空间失败");
        //exit(0);                  //开辟空间失败可以考虑直接结束程序
    }
    L->next=NULL;       //指针指向空
}

创建单链表(头插入法)

使用头插入法最终得到的结果是逆序的

//单链表的建立1,头插法建立单链表
LinkedList LinkedListCreatH() {
    Node *L;
    L = (Node *)malloc(sizeof(Node));   //申请头结点空间
    L->next = NULL;                      //初始化一个空链表
  
    int x;                         //x为链表数据域中的数据
    while(scanf("%d",&x) != EOF) {
        Node *p;
        p = (Node *)malloc(sizeof(Node));   //申请新的结点
        p->data = x;                     //结点数据域赋值
        p->next = L->next;     //将结点插入到表头L-->|2|-->|1|-->NULL
        L->next = p;
    }
    return L;

创建单链表(尾插入法)

希望两者次序一致,可采用尾插法

//单链表的建立2,尾插法建立单链表
  
LinkedList LinkedListCreatT() {
    Node *L;
    L = (Node *)malloc(sizeof(Node));   //申请头结点空间
    L->next = NULL;                  //初始化一个空链表
    Node *r;
    r = L;                          //r始终指向终端结点,开始时指向头结点
    int x;                         //x为链表数据域中的数据
    while(scanf("%d",&x) != EOF) {
        Node *p;
        p = (Node *)malloc(sizeof(Node));   //申请新的结点
        p->data = x;                     //结点数据域赋值
        r->next = p;            //将结点插入到表头L-->|1|-->|2|-->NULL
        r = p;
    }
    r->next = NULL;
    return L;
}

遍历单链表

  • 遍历打印输出
//便利输出单链表
void printList(LinkedList L){
    Node *p=L->next;
    int i=0;
    while(p){
        printf("第%d个元素的值为:%d\n",++i,p->data);
        p=p->next;
    }
}
  • 便利修改
//链表内容的修改,再链表中修改值为x的元素变为为k。
LinkedList LinkedListReplace(LinkedList L,int x,int k) {
    Node *p=L->next;
    int i=0;
    while(p){
        if(p->data==x){
            p->data=k;
        }
        p=p->next;
    }
    return L;
}

链表插入操作

//单链表的插入,在链表的第i个位置插入x的元素
  
LinkedList LinkedListInsert(LinkedList L,int i,int x) {
    Node *pre;                      //pre为前驱结点
    pre = L;
    int tempi = 0;
    for (tempi = 1; tempi < i; tempi++) {
        pre = pre->next;                 //查找第i个位置的前驱结点
    }
    Node *p;                                //插入的结点为p
    p = (Node *)malloc(sizeof(Node));
    p->data = x;
    p->next = pre->next;
    pre->next = p;
  
    return L;
}

链表删除操作

//单链表的删除,在链表中删除值为x的元素
  
LinkedList LinkedListDelete(LinkedList L,int x) {
    Node *p,*pre;                   //pre为前驱结点,p为查找的结点。
    p = L->next;
     
    while(p->data != x) {              //查找值为x的元素
        pre = p;
        p = p->next;
    }
    pre->next = p->next;          //删除操作,将其前驱next指向其后继。
    free(p);
     
    return L;
}
如果您觉得这篇文章不错,且手里较为宽裕,可以支持一下博主,一分也是缘分😊
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇