C语言强化学习第二天(单链表)

英文:
next:下一个
prev:上一个
list:链表
head:头
tail:尾
node:节点

回顾:
1.文件操作库函数
fopen/fclose/fread/fwrite/rewind/fseek
2.结构体数组
3.结构体和函数指针配合
4.Makefile提升:
4.1.伪目标:没有依赖的目标
例如:clean:
rm helloworld helloworld.o
当执行make clean时执行对应的命令
4.2.Makefile的变量
Makefile的变量类似C语言的#define宏,提高Makefile的可移植性
变量名建议用大写
定义形式:
a) OBJ=helloworld.o
b) OBJ:=helloworld.o
c) OBJ = helloworld.o
OBJ += test.o #结果OBJ=helloworld.o test.o
d)OBJ ?= helloworld.o #结果OBJ=helloworld.o
或者
OBJ = test.o
OBJ ?= helloworld.o #结果:OBJ=test.o
e)引用变量值用:$(OBJ)

#定义变量
BIN=list3_test

OBJ=list3_test.o 
OBJ+=list3.o

#CROSS_COMPILE=arm-linux-
CC=$(CROSS_COMPILE)gcc #CC=arm-linux-gcc / CC=gcc

#制定规则
$(BIN):$(OBJ)
	$(CC) -o $(BIN) $(OBJ)
	@echo "程序编译完成"

%.o:%.c
	$(CC) -c -o $@ $<

clean:
	rm $(OBJ) $(BIN)
	@echo "文件清理完毕"


4.数据结构
描述数据的关系和数据的存储方式
分类:
逻辑结构
集合结构
强调整体,不强调数据之间的关系
线性结构
一对一的前后关系
树形结构
一对多的关系
网状结构
多对多的关系
物理结构
顺序
数组
链式
链表
运算结构

5.数据结构实现方式:栈,队列,单链表,双链表,有序二叉树
5.1.栈
先进后出/后进先出
只操作栈顶
5.2.队列
FIFO:先进先出
经典的三大队列:消息队列,工作队列,等待队列
5.3.单链表
特点:体现一对一的前后关系
节点的数据结构:
struct node {
数据;
struct node *next; //指向下一个节点,多余占4字节
};
链表的数据结构:
struct list {
head;
tail;
};
注意:每个节点的内存不一定连续,不像数组一样连续
在这里插入图片描述

/*单链表初级代码*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //memset
//声明描述每个节点信息的数据结构
typedef struct node {
    int data; //数据
    struct node *next; //保存下一个节点的首地址
}node_t;
//声明描述整个单链表的数据结构
typedef struct list {
    struct node *head; //指向头节点
    struct node *tail; //指向尾节点
}list_t;
int main(void)
{
    //1.定义链表并且初始化头节点和尾节点
    list_t list;
    list.head = (node_t *)malloc(sizeof(node_t)); 
    list.tail = (node_t *)malloc(sizeof(node_t));
    memset(list.head, 0, sizeof(node_t));
    memset(list.tail, 0, sizeof(node_t));
    //2.定义三个节点
    node_t node1 = {.data = 10, .next = NULL};
    node_t node2 = {.data = 20, .next = NULL};
    node_t node3 = {.data = 30, .next = NULL};
    //3.将三个节点和链表的头和尾连接起来
    list.head->next = &node1;
    node1.next = &node2;
    node2.next = &node3;
    node3.next = list.tail;
    //4.遍历链表,打印每个节点的数据
    for(node_t *pnode = list.head; 
            pnode != list.tail; pnode=pnode->next) {
        //5.定义三个游标
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid != list.tail)
            printf("%d ", pmid->data);
    }
    printf("\n");
    //5.由小到大插入一个节点:15
    node_t node4 = {.data = 15, .next = NULL}; //造节点15
    for(node_t *pnode = list.head;
            pnode != list.tail; pnode=pnode->next) {
        //定义三个游标
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid->data > node4.data || pmid == list.tail) {
            pfirst->next = &node4;
            node4.next = pmid;
            break;
        } 
    } 
    //6.遍历链表,打印每个节点的数据
    for(node_t *pnode = list.head; 
            pnode != list.tail; pnode=pnode->next) {
        //定义三个游标
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid != list.tail)
            printf("%d ", pmid->data);
    }
    printf("\n");
    //7.前插:总是插入到head和第一个节点之间,例如node5
    node_t node5 = {.data = 5, .next = NULL};
    node_t *pnode = list.head->next; //先获取第一个节点的地址,临时保存
    list.head->next = &node5;
    node5.next = pnode;
   
    node_t node6 = {.data = 2, .next = NULL};
    pnode = list.head->next; //先获取第一个节点的地址,临时保存
    list.head->next = &node6;
    node6.next = pnode;
    //8.遍历链表,打印每个节点的数据
    for(node_t *pnode = list.head; 
            pnode != list.tail; pnode=pnode->next) {
        //定义三个游标
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid != list.tail)
            printf("%d ", pmid->data);
    }
    printf("\n");

    //9.后插:总是插入到tail和最后一个节点之间,例如:node6
    node_t node7 = {.data = 50, .next = NULL};
    for(node_t *pnode = list.head; 
            pnode != list.tail; pnode=pnode->next) {
        //定义三个游标
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid == list.tail) {
            //pfirst指向最后一个节点,pmid指向尾节点
            pfirst->next = &node7;
            node7.next = pmid;
            break;
        }
    }
    //10.遍历链表,打印每个节点的数据
    for(node_t *pnode = list.head; 
            pnode != list.tail; pnode=pnode->next) {
        //定义三个游标
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid != list.tail)
            printf("%d ", pmid->data);
    }
    printf("\n");
    //11.删除20这个节点
    for(node_t *pnode = list.head; 
            pnode != list.tail; pnode=pnode->next) {
        //定义三个游标
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid->data == 20 && pmid != list.tail) {
            pfirst->next = plast;    
        }
    }
    //12.遍历链表,打印每个节点的数据
    for(node_t *pnode = list.head; 
            pnode != list.tail; pnode=pnode->next) {
        //定义三个游标
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid != list.tail)
            printf("%d ", pmid->data);
    }
    printf("\n");
    return 0;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值