数据结构实战

内容概述

实例代码

01_顺序表

list.h文件
#ifndef _LIST_H
#define _LIST_H

// 定义元素类型,取别名,方便使用时修改类型
typedef int elem_t;

// 定义顺序表的容量(大小)
#define LIST_SIZE 100

// 定义顺序表:数组表示存储空间,整数表示已存储的元素个数
typedef struct {
    elem_t data[LIST_SIZE];
    int length;
} list_t;

// 初始化顺序表
void list_init(list_t *plist);

// 在指定位置插入元素
int list_insert(list_t *plist, int index, elem_t *pe);

// 删除指定位置的元素
int list_delete(list_t *plist, int index, elem_t *pe);

// 判断顺序表是否为空
static inline int list_is_empty(list_t *plist)
{
    // 利用 && 的短路特性
    return plist && (plist->length == 0);
}

// 判断顺序表是否已满
static inline int list_is_full(list_t *plist)
{
    return plist && (plist->length >= LIST_SIZE);
}

#endif
list.c文件
#include "list.h"
#include <string.h>

/**
  * 简述:初始化顺序表
  * 参数:plist 顺序表的指针,空指针不做处理
  * 返回值:无
  **/
void list_init(list_t *plist)
{
    if (plist) {
	plist->length = 0;  // 只需要将 length 清 0 即可,无须清 0 data 数组
    }     
}

/**
 * 简述:在指定位置插入元素
 * 参数:plist 顺序表的指针
 *       index 要插入的位置
 *       pe    要插入的元素的指针
 * 返回值:成功返回 0,失败返回 -1
 */
int list_insert(list_t *plist, int index, elem_t *pe)
{
    // 检查 plist 是否为 NULL,或是否已满,或者超范围
    if (!plist || list_is_full(plist) || index < 0 \
	    || index > plist->length) {
	return -1;
    }

    // 1. 将 index 处腾空,index 及其后的元素全部后移一位,注意从后面开始移动
    for (int i = plist->length; i > index; i--) {
	memcpy(&plist->data[i], &plist->data[i - 1], sizeof (elem_t));
    }
    // 2. 将元素 pe 放入到 index 处
    // plist->data + index 等价于 &plist->data[index]
    memcpy(plist->data + index, pe, sizeof (elem_t));
    // memcpy(&plist->data[index], pe, sizeof (elem_t));

    // 3. 顺序表长度自增
    plist->length++;

    return 0;  // 成功
}

// 删除指定位置的元素
/**
 * 简述:删除指定位置的元素
 * 参数:plist 顺序表指针
 *       index 要删除的元素的索引
 *       pe    保存被删除元素的指针,如果为 NULL 则不保存元素
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_delete(list_t *plist, int index, elem_t *pe)
{
    // 检查 plist 是否为 NULL,或是否已空,或者超出范围
    if (!plist || list_is_empty(plist) || index < 0 || index >= plist->length) {
	return -1;
    }
    // 1. 保存元素
    if (pe) {
	memcpy(pe, plist->data + index, sizeof (elem_t));
    }
    // 2. index 后面的元素逐个前移
    for (int i = index; i < plist->length - 1; i++) {
	memcpy(&plist->data[i], &plist->data[i + 1], sizeof (elem_t));
    }
    // 3. 长度自减
    plist->length--;

    return 0;
}
mian.c文件
#include <stdio.h>
#include "list.h"

void print_array(elem_t *array, int len)
{
    for (int i = 0; i < len; i++) {
	printf("%d\n", array[i]);
    }
}

int main(void)
{
    list_t list1;
    elem_t e;

    // 初始化顺序表
    list_init(&list1);

    // 插入一些元素
    for (int i = 0; i < 5; i++) {
	list_insert(&list1, 0, &i);
    }

    // 打印顺序表元素
    print_array(list1.data, list1.length);

    // 删除一个元素
    list_delete(&list1, 2, &e);
    print_array(list1.data, list1.length);
    printf("删除的元素是:%d\n", e);

    // 删除非法位置的元素
    printf("删除是否成功?%d\n", list_delete(&list1, 10, NULL));

    return 0;
}

02_单链表

list.h文件
#ifndef _LIST_H
#define _LIST_H

// 为元素类型取别名
typedef int elem_t;

// 定义节点类型
typedef struct node {
    elem_t data;   // 存放单个数据
    struct node *next;  // 存放下一个元素的地址
} node_t;


// 定义单链表类型
typedef struct {
   // 头节点,它是哑节点,即不保存数据的节点,通过它可以找到链表中的第一个元素
    node_t head;
    int length;    // 表长
} list_t;

// 初始化单链表
void list_init(list_t *plist);

// 在指定位置插入元素
int list_insert(list_t *plist, int index, elem_t *pe);

// 在指定位置删除元素
int list_delete(list_t *plist, int index, elem_t *pe);

// 判断单链表是否为空
static inline int list_is_empty(list_t *plist)
{
    return plist && (plist->length == 0);
}

// 销毁单链表
void list_destroy(list_t *plist);

#endif
list.c文件
#include "list.h"
#include <stdlib.h>
#include <string.h>

/**
 * 简述:初始化单链表
 * 参数:plist 单链表指针
 * 返回值:无
 **/
void list_init(list_t *plist)
{
    if (plist) {
	plist->head.next = NULL;  // 初始时头节点指向 NULL
	plist->length = 0;
    }
}

/**
 * 简述:在指定位置插入元素
 * 参数:plist 单链表指针
 *       index 插入索引号
 *       pe    插入的元素
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_insert(list_t *plist, int index, elem_t *pe)
{
    node_t *pnode, *pnew;

    // 检查参数
    if (!plist || !pe || index < 0 || index > plist->length) {
	return -1;
    }
    pnode = &plist->head;
    // 1. 找到 index 的前一个节点
    for (int i = 0; i < index; i++) {
	pnode = pnode->next;
    }
    // 2. 为新节点分配内存
    pnew = malloc(sizeof (node_t));
    // 3. 将元素值复制到新节点
    memcpy(&pnew->data, pe, sizeof (elem_t));
    // 4. 新节点链入到链表中
    pnew->next = pnode->next;
    pnode->next = pnew;
    // 5. 表长自增
    plist->length++;

    return 0;
}

/**
 * 简述:在指定位置删除元素
 * 参数:plist 单链表指针
 *       index 删除索引号
 *       pe    返回删除的元素,如果为 NULL 则不返回
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_delete(list_t *plist, int index, elem_t *pe)
{
    node_t *pnode, *pdel, *pnext;
    // 检查参数
    if (!plist || index < 0 || index >= plist->length) {
	return -1;
    }
    pnode = &plist->head;
    // 1. 找到 index 的前一个节点
    for (int i = 0; i < index; i++) {
	pnode = pnode->next;
    }
    // 2. 删除节点
    pdel = pnode->next;   // pdel 指向删除节点
    pnext = pdel->next;   // pnext 指向删除点的下一个节点
    pnode->next = pnext;  // 前一个节点指向后一个节点
    pdel->next = NULL;    // 删除节点指向 NULL
    // 3. 删除元素的值返回给调用者
    if (pe) {  // 调用者需要则返回给调用者
        memcpy(pe, &pdel->data, sizeof (elem_t));
    }
    // 4. 释放节点内存
    free(pdel);
    // 5. 表长自减
    plist->length--;

    return 0;
}

/**
 * 简述:销毁单链表
 * 参数:plist 单链表指针
 * 返回值:无
 **/
void list_destroy(list_t *plist)
{
    // 作业
}
main.c文件
#include <stdio.h>
#include "list.h"

// 打印链表元素值
void print_list(list_t *plist)
{
    node_t *pnode = plist->head.next;  // 从第一个节点开始
    
    while (pnode) {
	printf("%d ", pnode->data);
	pnode = pnode->next;
    }
}

int main(void)
{
    list_t list1;

    // 初始化
    list_init(&list1);

    // 插入元素
    for (int i = 10; i < 15; i++) {
	list_insert(&list1, 0, &i);
    }

    // 打印链表
    printf("链表元素值:");
    print_list(&list1);
    printf("\n");

    // 删除元素
    list_delete(&list1, 3, NULL);

    printf("链表元素值:");
    print_list(&list1);
    printf("\n");

    return 0;
}

03_双链表

list.h文件
#ifndef _LIST_H
#define _LIST_H

// 元素类型别名
typedef int elem_t;

// 节点类型
typedef struct __node {
    elem_t data;
    struct __node *prev, *next;
} node_t;

// 双链表类型
typedef struct {
    node_t head;   // 头节点
    int length;
} list_t;

// 初始化双链表
void list_init(list_t *plist);

// 向指定位置插入元素
int list_insert(list_t *plist, int index, elem_t *pe);

// 从指定位置删除元素
int list_delete(list_t *plist, int index, elem_t *pe);

// 销毁双链表
void list_destroy(list_t *plist);

#endif
list.c文件
#include "list.h"
#include <stdlib.h>
#include <string.h>

/**
 * 简述:初始化双链表
 * 参数:plist 双链表指针
 * 返回值:无
 **/
void list_init(list_t *plist)
{
    if (plist) {
	plist->head.prev = plist->head.next = NULL;
	plist->length = 0;
    }
}

/**
 * 简述:向指定位置插入元素
 * 参数:plist 双链表指针
 *       index 插入位置索引号
 *       pe    插入元素指针
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_insert(list_t *plist, int index, elem_t *pe)
{
    node_t *pnode, *pprev, *pnext, *pnew;

    // 检查参数
    if (!plist || !pe || index < 0 || index > plist->length) {
	return -1;
    }

    pnode = &plist->head;
    // 定位到插入点前一个节点
    for (int i = 0; i < index; i++) {
	pnode = pnode->next;
    }
    pprev = pnode;
    pnext = pnode->next;

    // 为新节点分配内存
    pnew = malloc(sizeof (node_t));
    // 复制元素到新节点
    memcpy(&pnew->data, pe, sizeof (elem_t));

    // 插入新节点
    pnew->prev = pprev;
    pnew->next = pnext;
    pprev->next = pnew;
    if (pnext) pnext->prev = pnew;  // 注意!避免空指针

    // 表长自增
    plist->length++;

    return 0;
}

/**
 * 简述:从指定位置删除元素
 * 参数:plist 双链表指针
 *       index 删除位置索引号
 *       pe    保存删除元素的指针,如果为 NULL 则不保存
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_delete(list_t *plist, int index, elem_t *pe)
{
    node_t *pnode, *pprev, *pnext, *pdel;

    // 检查参数
    if (!plist || index < 0 || index >= plist->length) {
	return -1;
    }

    pnode = &plist->head;
    // 定位到删除节点
    for (int i = 0; i <= index; i++) {
	pnode = pnode->next;
    }
    pdel = pnode;
    pprev = pdel->prev;
    pnext = pdel->next;

    // 删除节点
    pprev->next = pnext;
    if (pnext) pnext->prev = pprev;   // 注意!避免空指针
    pdel->prev = NULL;
    pdel->next = NULL;

    // 保存删除节点的数据
    if (pe) {
	memcpy(pe, &pdel->data, sizeof (elem_t));
    }

    // 释放节点内存
    free(pdel);

    // 表长自减
    plist->length--;

    return 0;
}

/**
 * 简述:销毁双链表
 * 参数:plist 双链表指针
 * 返回值:无
 **/
void list_destroy(list_t *plist)
{
    node_t *pnode, *pnext;

    if (!plist) {
	return;
    }

    // 从第一个节点开始销毁
    pnode = plist->head.next;
    while (pnode) {
	pnext = pnode->next;  // 先记住下一个节点
	free(pnode);   // 释放当前节点
	pnode = pnext; // 指向下一个节点
    }

    // 链表全部节点都已销毁,重新初始化即可
    list_init(plist);
}
main.c文件
#include <stdio.h>
#include "list.h"

// 打印双链表
void print_list(list_t *plist)
{
    node_t *pnode;

    if (!plist) return;

    pnode = plist->head.next;
    while (pnode) {
	printf("%d ", pnode->data);
	pnode = pnode->next;
    }
}

int main(void)
{
    list_t list1;
    elem_t e;

    // 初始化双链表
    list_init(&list1);

    // 插入数据
    for (int i = 20; i < 26; i++) {
	list_insert(&list1, 0, &i);
    }

    // 打印双链表
    printf("双链表元素:");
    print_list(&list1);
    printf("\n");

    // 删除元素
    list_delete(&list1, 2, &e);
    printf("删除的元素值 = %d\n", e);

    // 打印双链表
    printf("删除后双链表元素:");
    print_list(&list1);
    printf("\n");

    // 插入元素
    e = 100;
    if (-1 == list_insert(&list1, 20, &e)) {
	printf("插入元素 %d 失败\n", e);
    }

    // 删除末尾元素
    if (-1 == list_delete(&list1, 5, NULL)) {
	printf("删除索引 5 处元素失败\n");
    }

    // 链表在使用完之后,动态分配的内存必须释放,否则带来内存泄露,最终会导致内存溢出
    list_destroy(&list1);

    return 0;
}

04_单循环链表

list.h文件
#ifndef _LIST_H
#define _LIST_H

// 数据类型别名
typedef int elem_t;

// 节点类型
typedef struct __node {
    elem_t data;
    struct __node *next;
} node_t;

// 单循环链表类型
typedef struct {
    node_t head;
    int length;
} list_t;

// 初始化单循环链表
void list_init(list_t *plist);

// 向指定位置插入元素
int list_insert(list_t *plist, int index, elem_t *pe);

// 从指定位置删除元素
int list_delete(list_t *plist, int index, elem_t *pe);

// 销毁单循环链表
void list_destroy(list_t *plist);

#endif
list.c文件
#include <stdlib.h>
#include <string.h>
#include "list.h"

/**
 * 简述:初始化单循环链表
 * 参数:plist 单循环链表指针
 * 返回值:无
 **/
void list_init(list_t *plist)
{
    if (plist) {
	plist->head.next = &plist->head;  // 头节点指向自己
	plist->length = 0;
    }
}

/**
 * 简述:插入节点
 * 参数:pprev 前节点指针
 *       pnext 后节点指针
 *       pnew  新节点指针
 * 返回值:无
 **/
static inline void __list_insert_between(node_t *pprev, node_t *pnext, node_t *pnew)
{
    pnew->next = pnext;
    pprev->next = pnew;
}

/**
 * 简述:向指定位置插入元素
 * 参数:plist 单循环链表指针
 *       index 插入位置索引
 *       pe    元素指针
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_insert(list_t *plist, int index, elem_t *pe)
{
    node_t *pnode, *pprev, *pnext, *pnew;

    // 检查参数
    if (!plist || !pe || index < 0 || index > plist->length) {
	return -1;
    }

    // 找到插入点的前一个节点
    pnode = &plist->head;
    for (int i = 0; i < index; i++) {
	pnode = pnode->next;
    }
    pprev = pnode;
    pnext = pnode->next;

    // 为新节点分配内存
    pnew = malloc(sizeof (node_t));

    // 复制数据到新节点
    memcpy(&pnew->data, pe, sizeof (elem_t));

    // 链入链表
    __list_insert_between(pprev, pnext, pnew);
    // 以下是等价的,少使用两个指针变量
    //__list_insert_between(pnode, pnode->next, pnew);

    // 表长自增
    plist->length++;

    return 0;
}


/**
 * 简述:从指定位置删除元素
 * 参数:plist 单循环链表指针
 *       index 插入位置索引
 *       pe    保存元素的指针,如果为 NULL,则不保存
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_delete(list_t *plist, int index, elem_t *pe)
{
    node_t *pnode, *pprev, *pnext, *pdel;

    // 检查参数
    if (!plist || index < 0 || index >= plist->length) {
	return -1;
    }

    // 找到删除点前一个节点
    pnode = &plist->head;
    for (int i = 0; i < index; i++) {
	pnode = pnode->next;
    }
    pprev = pnode;       // 删除点前一个节点
    pdel = pnode->next;  // 删除点
    pnext = pdel->next;  // 删除点后一个节点

    // 从链表中摘除
    pprev->next = pnext;
    pdel->next = NULL;

    // 保存元素数据
    if (pe) {
	memcpy(pe, &pdel->data, sizeof (elem_t));
    }

    // 释放节点内存
    free(pdel);

    // 表长自减
    plist->length--;

    return 0;
}

/**
 * 简述:销毁单循环链表
 * 参数:plist 单循环链表指针
 * 返回值:无
 **/
void list_destroy(list_t *plist)
{
    node_t *pnode, *pnext;

    if (!plist) return;
    
    pnode = plist->head.next;
    while (pnode != &plist->head) {  // 尾节点是指向头节点
	pnext = pnode->next;
	free(pnode);
	pnode = pnext;
    }

    list_init(plist);
}
main.c文件
#include <stdio.h>
#include "list.h"

// 打印单循环链表
void print_list(list_t *plist)
{
    node_t *pnode;
    
    if (!plist) return;

    pnode = plist->head.next;
    while (pnode != &plist->head) {
	printf("%d ", pnode->data);
	pnode = pnode->next;
    }
}


int main(void)
{
    list_t list1;
    elem_t e;

    // 初始化单循环链表
    list_init(&list1);
    
    // 插入元素
    for (int i = 100; i < 109; i++) {
	list_insert(&list1, 0, &i);
    }

    // 打印单循环链表
    printf("单循环链表元素:");
    print_list(&list1);
    printf("\n");

    // 删除元素
    if (0 == list_delete(&list1, 3, &e)) {
	printf("删除 %d 成功\n", e);
    }

    // 打印单循环链表
    printf("删除后单循环链表元素:");
    print_list(&list1);
    printf("\n");

    if (-1 == list_delete(&list1, -1, NULL)) {
	printf("删除 -1 处元素失败\n");
    }

    // 销毁单循环链表
    list_destroy(&list1);

    return 0;
}

05_双循环链表

list.h文件
#ifndef _LIST_H
#define _LIST_H

// 元素类型别名
typedef int elem_t;

// 节点类型
typedef struct __node {
    elem_t data;
    struct __node *prev, *next;
} node_t;

// 双链表类型
typedef struct {
    node_t head;   // 头节点
    int length;
} list_t;

// 初始化双链表
void list_init(list_t *plist);

// 向指定位置插入元素
int list_insert(list_t *plist, int index, elem_t *pe);

// 从指定位置删除元素
int list_delete(list_t *plist, int index, elem_t *pe);

// 销毁双链表
void list_destroy(list_t *plist);

#endif
list.c文件
#include "list.h"
#include <stdlib.h>
#include <string.h>

/**
 * 简述:初始化双循环链表
 * 参数:plist 双循环链表指针
 * 返回值:无
 **/
void list_init(list_t *plist)
{
    if (plist) {
	plist->head.prev = plist->head.next = &plist->head;
	plist->length = 0;
    }
}

/**
 * 简述:向指定位置插入元素
 * 参数:plist 双循环链表指针
 *       index 插入位置索引号
 *       pe    插入元素指针
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_insert(list_t *plist, int index, elem_t *pe)
{
    node_t *pnode, *pprev, *pnext, *pnew;

    // 检查参数
    if (!plist || !pe || index < 0 || index > plist->length) {
	return -1;
    }

    pnode = &plist->head;
    // 定位到插入点前一个节点
    for (int i = 0; i < index; i++) {
	pnode = pnode->next;
    }
    pprev = pnode;
    pnext = pnode->next;

    // 为新节点分配内存
    pnew = malloc(sizeof (node_t));
    // 复制元素到新节点
    memcpy(&pnew->data, pe, sizeof (elem_t));

    // 插入新节点
    pnew->prev = pprev;
    pnew->next = pnext;
    pprev->next = pnew;
    pnext->prev = pnew;

    // 表长自增
    plist->length++;

    return 0;
}

/**
 * 简述:从指定位置删除元素
 * 参数:plist 双循环链表指针
 *       index 删除位置索引号
 *       pe    保存删除元素的指针,如果为 NULL 则不保存
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_delete(list_t *plist, int index, elem_t *pe)
{
    node_t *pnode, *pprev, *pnext, *pdel;

    // 检查参数
    if (!plist || index < 0 || index >= plist->length) {
	return -1;
    }

    pnode = &plist->head;
    // 定位到删除节点
    for (int i = 0; i <= index; i++) {
	pnode = pnode->next;
    }
    pdel = pnode;
    pprev = pdel->prev;
    pnext = pdel->next;

    // 删除节点
    pprev->next = pnext;
    pnext->prev = pprev;
    pdel->prev = NULL;
    pdel->next = NULL;

    // 保存删除节点的数据
    if (pe) {
	memcpy(pe, &pdel->data, sizeof (elem_t));
    }

    // 释放节点内存
    free(pdel);

    // 表长自减
    plist->length--;

    return 0;
}

/**
 * 简述:销毁双循环链表
 * 参数:plist 双循环链表指针
 * 返回值:无
 **/
void list_destroy(list_t *plist)
{
    node_t *pnode, *pnext;

    if (!plist) {
	return;
    }

    // 从第一个节点开始销毁
    pnode = plist->head.next;
    while (pnode != &plist->head) {
	pnext = pnode->next;  // 先记住下一个节点
	free(pnode);   // 释放当前节点
	pnode = pnext; // 指向下一个节点
    }

    // 链表全部节点都已销毁,重新初始化即可
    list_init(plist);
}
main.c文件
#include <stdio.h>
#include "list.h"

// 打印双链表
void print_list(list_t *plist)
{
    node_t *pnode;

    if (!plist) return;

    pnode = plist->head.next;
    while (pnode) {
	printf("%d ", pnode->data);
	pnode = pnode->next;
    }
}

int main(void)
{
    list_t list1;
    elem_t e;

    // 初始化双链表
    list_init(&list1);

    // 插入数据
    for (int i = 20; i < 26; i++) {
	list_insert(&list1, 0, &i);
    }

    // 打印双链表
    printf("双链表元素:");
    print_list(&list1);
    printf("\n");

    // 删除元素
    list_delete(&list1, 2, &e);
    printf("删除的元素值 = %d\n", e);

    // 打印双链表
    printf("删除后双链表元素:");
    print_list(&list1);
    printf("\n");

    // 插入元素
    e = 100;
    if (-1 == list_insert(&list1, 20, &e)) {
	printf("插入元素 %d 失败\n", e);
    }

    // 删除末尾元素
    if (-1 == list_delete(&list1, 5, NULL)) {
	printf("删除索引 5 处元素失败\n");
    }

    // 链表在使用完之后,动态分配的内存必须释放,否则带来内存泄露,最终会导致内存溢出
    list_destroy(&list1);

    return 0;
}

06_合并有序单链表

list.h文件
#ifndef _LIST_H
#define _LIST_H

// 为元素类型取别名
typedef int elem_t;

// 定义节点类型
typedef struct node {
    elem_t data;   // 存放单个数据
    struct node *next;  // 存放下一个元素的地址
} node_t;


// 定义单链表类型
typedef struct {
   // 头节点,它是哑节点,即不保存数据的节点,通过它可以找到链表中的第一个元素
    node_t head;
    int length;    // 表长
} list_t;

// 初始化单链表
void list_init(list_t *plist);

// 在指定位置插入元素
int list_insert(list_t *plist, int index, elem_t *pe);

// 在指定位置删除元素
int list_delete(list_t *plist, int index, elem_t *pe);

// 判断单链表是否为空
static inline int list_is_empty(list_t *plist)
{
    return plist && (plist->length == 0);
}

// 销毁单链表
void list_destroy(list_t *plist);

// 合并有序单链表
int list_merge_order(list_t *dst, list_t *src);

#endif
list.c文件
#include "list.h"
#include <stdlib.h>
#include <string.h>

/**
 * 简述:初始化单链表
 * 参数:plist 单链表指针
 * 返回值:无
 **/
void list_init(list_t *plist)
{
    if (plist) {
	plist->head.next = NULL;  // 初始时头节点指向 NULL
	plist->length = 0;
    }
}

/**
 * 简述:在指定位置插入元素
 * 参数:plist 单链表指针
 *       index 插入索引号
 *       pe    插入的元素
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_insert(list_t *plist, int index, elem_t *pe)
{
    node_t *pnode, *pnew;

    // 检查参数
    if (!plist || !pe || index < 0 || index > plist->length) {
	return -1;
    }
    pnode = &plist->head;
    // 1. 找到 index 的前一个节点
    for (int i = 0; i < index; i++) {
	pnode = pnode->next;
    }
    // 2. 为新节点分配内存
    pnew = malloc(sizeof (node_t));
    // 3. 将元素值复制到新节点
    memcpy(&pnew->data, pe, sizeof (elem_t));
    // 4. 新节点链入到链表中
    pnew->next = pnode->next;
    pnode->next = pnew;
    // 5. 表长自增
    plist->length++;

    return 0;
}

/**
 * 简述:在指定位置删除元素
 * 参数:plist 单链表指针
 *       index 删除索引号
 *       pe    返回删除的元素,如果为 NULL 则不返回
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_delete(list_t *plist, int index, elem_t *pe)
{
    node_t *pnode, *pdel, *pnext;
    // 检查参数
    if (!plist || index < 0 || index >= plist->length) {
	return -1;
    }
    pnode = &plist->head;
    // 1. 找到 index 的前一个节点
    for (int i = 0; i < index; i++) {
	pnode = pnode->next;
    }
    // 2. 删除节点
    pdel = pnode->next;   // pdel 指向删除节点
    pnext = pdel->next;   // pnext 指向删除点的下一个节点
    pnode->next = pnext;  // 前一个节点指向后一个节点
    pdel->next = NULL;    // 删除节点指向 NULL
    // 3. 删除元素的值返回给调用者
    if (pe) {  // 调用者需要则返回给调用者
        memcpy(pe, &pdel->data, sizeof (elem_t));
    }
    // 4. 释放节点内存
    free(pdel);
    // 5. 表长自减
    plist->length--;

    return 0;
}

/**
 * 简述:销毁单链表
 * 参数:plist 单链表指针
 * 返回值:无
 **/
void list_destroy(list_t *plist)
{
    // 作业
}

// 在两个节点之间插入新节点
static inline void __list_insert_between(node_t *pprev, node_t *pnext, node_t *pnew)
{
    pnew->next = pnext;
    pprev->next = pnew;
}

/**
 * 简述:合并有序单链表
 * 参数:dst 目标单链表
 *       src 源单链表
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_merge_order(list_t *dst, list_t *src)
{
    node_t *pd1, *pd2, *ps1, *ps2;

    if (!dst) return -1;
    if (!src) return 0;   // src 为 NULL 则不需要合并
   
    pd1 = &dst->head;
    pd2 = pd1->next;
    ps1 = src->head.next; 
    ps2 = ps1->next;

    while (pd2) {
	// 比较 pd2 与 ps1 的值
	if (ps1->data < pd2->data) {
	    // 将 ps1 插入到 pd1 和 pd2 之间
	    __list_insert_between(pd1, pd2, ps1);
	    //dst->length++;
	    //src->length--;
	    pd1 = ps1;
	    if (!ps2) break;  // src 结束则退出循环 
	    ps1 = ps2;
	    ps2 = ps2->next;
	} else {   // 不需要插入,则 pd1 和 pd2 向后走一步
	    pd1 = pd2;
	    pd2 = pd2->next;
	}
    }	

    if (!pd2) {   // dst 到尾了,将 src 的剩余节点链入 dst
	pd1->next = ps1;
	//dst->length += src->length;
	//src->length = 0;
	//src->head.next = NULL;
    }

    dst->length += src->length;
    list_init(src);

    return 0;
}
main.c文件
#include <stdio.h>
#include "list.h"

// 打印链表元素值
void print_list(list_t *plist)
{
    node_t *pnode = plist->head.next;  // 从第一个节点开始
    
    while (pnode) {
	printf("%d ", pnode->data);
	pnode = pnode->next;
    }
}

int main(void)
{
    elem_t data1[] = {1, 10, 15};
    elem_t data2[] = {-3, 12, 20};
    list_t list1, list2;

    // 初始化
    list_init(&list1);
    list_init(&list2);

    // 插入元素
    for (int i = 2; i >= 0; i--) {
	list_insert(&list1, 0, data1 + i);
    }

    // 插入元素
    for (int i = 2; i >= 0; i--) {
	list_insert(&list2, 0, data2 + i);
    }

    // 打印链表
    printf("链表 1 元素值:");
    print_list(&list1);
    printf("\n");
    printf("链表 2 元素值:");
    print_list(&list2);
    printf("\n");

    // 合并 list2 到 list1
    list_merge_order(&list1, &list2);

    printf("链表 1 元素值:");
    print_list(&list1);
    printf("\n");

    printf("链表 1 长度为:%d,链表 2 长度为:%d\n", list1.length, list2.length);

    return 0;
}

07_通用链表

list.h文件
#ifndef _LIST_H
#define _LIST_H

#include <stdio.h>

// 定义通用链表节点类型,不包含数据,只有指针
typedef struct node {
    struct node *next;  // 存放下一个元素的地址
} node_t;

// 初始化通用链表
void list_init(node_t *phead);

// 在指定位置插入元素
int list_insert(node_t *phead, int index, node_t *pnew);

// 在指定位置删除元素
int list_delete(node_t *phead, int index);

// 判断通用链表是否为空
static inline int list_is_empty(node_t *phead)
{
    return phead->next == NULL;
}

// 销毁通用链表
void list_destroy(node_t *phead);

#endif
list.c文件
#include "list.h"
#include <stdlib.h>
#include <string.h>

/**
 * 简述:初始化通用链表
 * 参数:phead 通用链表头指针
 * 返回值:无
 **/
void list_init(node_t *phead)
{
    if (phead) {
	phead->next = NULL;  // 初始时头节点指向 NULL
    }
}

/**
 * 简述:在指定位置插入元素
 * 参数:phead 通用链表头指针
 *       index 插入索引号
 *       pnew  插入的节点指针
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_insert(node_t *phead, int index, node_t *pnew)
{
    node_t *pnode;

    // 检查参数
    if (!phead || !pnew) {
	return -1;
    }
    if (index < 0) index = 0;
    pnode = phead;
    // 1. 找到 index 的前一个节点
    for (int i = 0; i < index && pnode->next; i++) {
	pnode = pnode->next;
    }
    // 2. 新节点链入到链表中
    pnew->next = pnode->next;
    pnode->next = pnew;

    return 0;
}

// 求链表长度
int list_length(node_t *phead)
{
    int length = 0;

    if (!phead) return 0;
    
    while (phead->next) {
	length++;
	phead = phead->next;
    }

    return length;
}

/**
 * 简述:在指定位置删除元素
 * 参数:phead 通用链表头指针
 *       index 删除索引号
 * 返回值:成功返回 0,失败返回 -1
 **/
int list_delete(node_t *phead, int index)
{
    node_t *pnode, *pdel, *pnext;
    // 检查参数
    if (!phead) {
	return -1;
    }
    if (index < 0) index = 0;
    if (index >= list_length(phead)) {
	index = list_length(phead) - 1;
    }
    pnode = phead;
    // 1. 找到 index 的前一个节点
    for (int i = 0; i < index; i++) {
	pnode = pnode->next;
    }
    // 2. 删除节点
    pdel = pnode->next;   // pdel 指向删除节点
    pnext = pdel->next;   // pnext 指向删除点的下一个节点
    pnode->next = pnext;  // 前一个节点指向后一个节点
    pdel->next = NULL;    // 删除节点指向 NULL
    // 3. 释放节点内存
    free(pdel);

    return 0;
}

/**
 * 简述:销毁通用链表
 * 参数:phead 通用链表头指针
 * 返回值:无
 **/
void list_destroy(node_t *phead)
{
    node_t *pnext;

    while (phead) {
	pnext = phead->next;
	free(phead);
	phead = pnext;	
    }

    phead->next = NULL;
}
int.h文件
#ifndef _INT_H
#define _INT_H

#include "list.h"

// 定义 int 节点类型
typedef struct {
    node_t node;  // 通用链表节点必须是第一个成员
    int data;
} intnode_t;

// 向指定位置插入元素
int int_list_insert(node_t *phead, int index, int data);

// 删除指定位置元素
int int_list_delete(node_t *phead, int index);

#endif
int.c文件
#include <stdlib.h>
#include "int.h"

// 向指定位置插入元素
int int_list_insert(node_t *phead, int index, int data)
{
    intnode_t *pnode;

    // 分配节点内存
    pnode = malloc(sizeof (intnode_t));
    // 复制数据
    pnode->data = data;
    // 插入链表
    if (-1 == list_insert(phead, index, (node_t *) pnode)) {
	free(pnode);
	return -1;
    }

    return 0;
}

// 删除指定位置元素
int int_list_delete(node_t *phead, int index)
{
    return list_delete(phead, index);
}
main.c文件
#include <stdio.h>
#include "int.h"

// 打印链表元素值
void print_int_list(node_t *phead)
{
    node_t *pnode = phead->next;  // 从第一个节点开始
    
    while (pnode) {
	printf("%d ", ((intnode_t *) pnode)->data);
	pnode = pnode->next;
    }
}

int main(void)
{
    node_t list1;

    // 初始化
    list_init(&list1);

    // 插入元素
    for (int i = 10; i < 15; i++) {
	int_list_insert(&list1, 0, i);
    }

    // 打印链表
    printf("链表元素值:");
    print_int_list(&list1);
    printf("\n");

    // 删除元素
    int_list_delete(&list1, 3);

    printf("链表元素值:");
    print_int_list(&list1);
    printf("\n");

    return 0;
}
stu.h文件
#ifndef _STUDENT_H
#define _STUDENT_H

#include "list.h"

// 学生类型
typedef struct {
    node_t node;   // 第一个成员必须是通用节点
    int no;
    char name[40];
} stunode_t;

// 插入学生信息
int stu_list_insert(node_t *phead, int index, int no, char *name);

#endif
stu.c文件
#include <stdlib.h>
#include <string.h>
#include "stu.h"

// 插入学生信息
int stu_list_insert(node_t *phead, int index, int no, char *name)
{
    // 分配新节点内存
    stunode_t *pnode = malloc(sizeof (stunode_t));

    // 复制数据
    pnode->no = no;
    strcpy(pnode->name, name);

    if (-1 == list_insert(phead, index, (node_t *) pnode)) {
	// 插入失败则释放内存
	free(pnode);
	return -1;
    }
    
    return 0;
}
main2.c文件

#include <stdio.h>
#include "stu.h"

// 打印链表元素值
void print_stu_list(node_t *phead)
{
    node_t *pnode = phead->next;  // 从第一个节点开始
    stunode_t *ps;

    while (pnode) {
	ps = (stunode_t *) pnode;
	printf("%d\t%s\n", ps->no, ps->name);
	pnode = pnode->next;
    }
}

int main(void)
{
    node_t list1;
    int nos[] = {1, 2, 3};
    char names[][40] = {"张三", "李四", "王五"};

    // 初始化
    list_init(&list1);

    // 插入元素
    for (int i = 0; i < 3; i++) {
	stu_list_insert(&list1, 0, nos[i], names[i]);
    }

    // 打印链表
    printf("链表元素值:");
    print_stu_list(&list1);
    printf("\n");

    // 删除元素
    list_delete(&list1, 1);

    printf("链表元素值:");
    print_stu_list(&list1);
    printf("\n");

    return 0;
}

08_linux链表

list.h文件
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H

// 此头文件取自内核源码包 linux-5.0.13.tar.xz 中的 include/linux/list.h

// 以下是移植过程:

// 1. 屏蔽以下内核头文件
//#include <linux/types.h>
//#include <linux/stddef.h>
//#include <linux/poison.h>
//#include <linux/const.h>
//#include <linux/kernel.h>

// 2. 包含以下头文件
#include <stdbool.h>   // bool 类型需要

// 3. 从 include/linux/types.h 中复制以下结构体
struct list_head {
	struct list_head *next, *prev;
};

struct hlist_head {
	struct hlist_node *first;
};

struct hlist_node {
	struct hlist_node *next, **pprev;
};

// 4. 从 include/linux/poison.h 中复制以下常量
#define POISON_POINTER_DELTA 0
#define LIST_POISON1  ((void *) 0x100 + POISON_POINTER_DELTA)
#define LIST_POISON2  ((void *) 0x200 + POISON_POINTER_DELTA)

// 5. 从 include/linux/stddef.h 中复制以下宏
#define offsetof(TYPE, MEMBER)      ((size_t)&((TYPE *)0)->MEMBER)

// 6. 从 include/linux/kernel.h 中复制以下宏
// 注:屏蔽 BUILD_BUG_ON_MSG() 调用
/**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:    the pointer to the member.
 * @type:   the type of the container struct this is embedded in.
 * @member: the name of the member within the struct.
 *
 */
#define container_of(ptr, type, member) ({              \
			void *__mptr = (void *)(ptr);                   \
			/*BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) &&   \
			  !__same_type(*(ptr), void),            \
			  "pointer type mismatch in container_of()");*/    \
			((type *)(__mptr - offsetof(type, member))); })

// 7. 增加以下类型别名
typedef unsigned char __u8;
typedef unsigned short __u16;
typedef unsigned int __u32;
typedef unsigned long __u64;

// 8. 从 include/linux/compiler.h 中复制以下函数和宏
// 注:屏蔽 barrier() 调用
static __always_inline void __write_once_size(volatile void *p, void *res, int  size)
{
	switch (size) {
		case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
		case 2: *(volatile __u16 *)p = *(__u16 *)res; break;
		case 4: *(volatile __u32 *)p = *(__u32 *)res; break;
		case 8: *(volatile __u64 *)p = *(__u64 *)res; break;
		default:
				//barrier();   
				__builtin_memcpy((void *)p, (const void *)res, size);
				//barrier(); 
	}
}
// 注:屏蔽 barrier() 调用
#define __READ_ONCE_SIZE                        \
	({                                  \
	 switch (size) {                         \
	 case 1: *(__u8 *)res = *(volatile __u8 *)p; break;      \
	 case 2: *(__u16 *)res = *(volatile __u16 *)p; break;        \
	 case 4: *(__u32 *)res = *(volatile __u32 *)p; break;        \
	 case 8: *(__u64 *)res = *(volatile __u64 *)p; break;        \
	 default:                            \
	 /*barrier(); */                     \
	 __builtin_memcpy((void *)res, (const void *)p, size);   \
	 /*barrier(); */                     \
	 }                               \
	 })

static __always_inline
void __read_once_size(const volatile void *p, void *res, int size)
{
	__READ_ONCE_SIZE;
}

// 注:__no_kasan_or_inline 改为 inline
static /*__no_kasan_or_inline*/ inline
void __read_once_size_nocheck(const volatile void *p, void *res, int size)
{
	__READ_ONCE_SIZE;
}

// 从 include/linux/compiler.h 中复制以下宏
// 注:屏蔽 __force
#define WRITE_ONCE(x, val) \
	({                          \
	 union { typeof(x) __val; char __c[1]; } __u =   \
	 { .__val = (/*__force*/ typeof(x)) (val) }; \
	 __write_once_size(&(x), __u.__c, sizeof(x));    \
	 __u.__val;                  \
	 })

// 注:屏蔽 smp_read_barrier_depends() 调用
#define __READ_ONCE(x, check)                       \
	({                                  \
	 union { typeof(x) __val; char __c[1]; } __u;            \
	 if (check)                          \
	 __read_once_size(&(x), __u.__c, sizeof(x));     \
	 else                                \
	 __read_once_size_nocheck(&(x), __u.__c, sizeof(x)); \
	 /*smp_read_barrier_depends();*/ /* Enforce dependency ordering from x */ \
	 __u.__val;                          \
	 })
#define READ_ONCE(x) __READ_ONCE(x, 1)


// ---------------------------------------------------------------------------

/*
 * Simple doubly linked list implementation.
 *
 * Some of the internal functions ("__xxx") are useful when
 * manipulating whole lists rather than single entries, as
 * sometimes we already know the next/prev entries and we can
 * generate better code by using them directly rather than
 * using the generic single-entry routines.
 */

#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
	struct list_head name = LIST_HEAD_INIT(name)

static inline void INIT_LIST_HEAD(struct list_head *list)
{
	WRITE_ONCE(list->next, list);
	list->prev = list;
}

#ifdef CONFIG_DEBUG_LIST
extern bool __list_add_valid(struct list_head *new,
			struct list_head *prev,
			struct list_head *next);
extern bool __list_del_entry_valid(struct list_head *entry);
#else
static inline bool __list_add_valid(struct list_head *new,
			struct list_head *prev,
			struct list_head *next)
{
	return true;
}
static inline bool __list_del_entry_valid(struct list_head *entry)
{
	return true;
}
#endif

/*
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __list_add(struct list_head *new,
			struct list_head *prev,
			struct list_head *next)
{
	if (!__list_add_valid(new, prev, next))
	  return;

	next->prev = new;
	new->next = next;
	new->prev = prev;
	WRITE_ONCE(prev->next, new);
}

/**
 * list_add - add a new entry
 * @new: new entry to be added
 * @head: list head to add it after
 *
 * Insert a new entry after the specified head.
 * This is good for implementing stacks.
 */
static inline void list_add(struct list_head *new, struct list_head *head)
{
	__list_add(new, head, head->next);
}


/**
 * list_add_tail - add a new entry
 * @new: new entry to be added
 * @head: list head to add it before
 *
 * Insert a new entry before the specified head.
 * This is useful for implementing queues.
 */
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
	__list_add(new, head->prev, head);
}

/*
 * Delete a list entry by making the prev/next entries
 * point to each other.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
	next->prev = prev;
	WRITE_ONCE(prev->next, next);
}

/**
 * list_del - deletes entry from list.
 * @entry: the element to delete from the list.
 * Note: list_empty() on entry does not return true after this, the entry is
 * in an undefined state.
 */
static inline void __list_del_entry(struct list_head *entry)
{
	if (!__list_del_entry_valid(entry))
	  return;

	__list_del(entry->prev, entry->next);
}

static inline void list_del(struct list_head *entry)
{
	__list_del_entry(entry);
	entry->next = LIST_POISON1;
	entry->prev = LIST_POISON2;
}

/**
 * list_replace - replace old entry by new one
 * @old : the element to be replaced
 * @new : the new element to insert
 *
 * If @old was empty, it will be overwritten.
 */
static inline void list_replace(struct list_head *old,
			struct list_head *new)
{
	new->next = old->next;
	new->next->prev = new;
	new->prev = old->prev;
	new->prev->next = new;
}

static inline void list_replace_init(struct list_head *old,
			struct list_head *new)
{
	list_replace(old, new);
	INIT_LIST_HEAD(old);
}

/**
 * list_del_init - deletes entry from list and reinitialize it.
 * @entry: the element to delete from the list.
 */
static inline void list_del_init(struct list_head *entry)
{
	__list_del_entry(entry);
	INIT_LIST_HEAD(entry);
}

/**
 * list_move - delete from one list and add as another's head
 * @list: the entry to move
 * @head: the head that will precede our entry
 */
static inline void list_move(struct list_head *list, struct list_head *head)
{
	__list_del_entry(list);
	list_add(list, head);
}

/**
 * list_move_tail - delete from one list and add as another's tail
 * @list: the entry to move
 * @head: the head that will follow our entry
 */
static inline void list_move_tail(struct list_head *list,
			struct list_head *head)
{
	__list_del_entry(list);
	list_add_tail(list, head);
}

/**
 * list_bulk_move_tail - move a subsection of a list to its tail
 * @head: the head that will follow our entry
 * @first: first entry to move
 * @last: last entry to move, can be the same as first
 *
 * Move all entries between @first and including @last before @head.
 * All three entries must belong to the same linked list.
 */
static inline void list_bulk_move_tail(struct list_head *head,
			struct list_head *first,
			struct list_head *last)
{
	first->prev->next = last->next;
	last->next->prev = first->prev;

	head->prev->next = first;
	first->prev = head->prev;

	last->next = head;
	head->prev = last;
}

/**
 * list_is_last - tests whether @list is the last entry in list @head
 * @list: the entry to test
 * @head: the head of the list
 */
static inline int list_is_last(const struct list_head *list,
			const struct list_head *head)
{
	return list->next == head;
}

/**
 * list_empty - tests whether a list is empty
 * @head: the list to test.
 */
static inline int list_empty(const struct list_head *head)
{
	return READ_ONCE(head->next) == head;
}

/**
 * list_empty_careful - tests whether a list is empty and not being modified
 * @head: the list to test
 *
 * Description:
 * tests whether a list is empty _and_ checks that no other CPU might be
 * in the process of modifying either member (next or prev)
 *
 * NOTE: using list_empty_careful() without synchronization
 * can only be safe if the only activity that can happen
 * to the list entry is list_del_init(). Eg. it cannot be used
 * if another CPU could re-list_add() it.
 */
static inline int list_empty_careful(const struct list_head *head)
{
	struct list_head *next = head->next;
	return (next == head) && (next == head->prev);
}

/**
 * list_rotate_left - rotate the list to the left
 * @head: the head of the list
 */
static inline void list_rotate_left(struct list_head *head)
{
	struct list_head *first;

	if (!list_empty(head)) {
		first = head->next;
		list_move_tail(first, head);
	}
}

/**
 * list_is_singular - tests whether a list has just one entry.
 * @head: the list to test.
 */
static inline int list_is_singular(const struct list_head *head)
{
	return !list_empty(head) && (head->next == head->prev);
}

static inline void __list_cut_position(struct list_head *list,
			struct list_head *head, struct list_head *entry)
{
	struct list_head *new_first = entry->next;
	list->next = head->next;
	list->next->prev = list;
	list->prev = entry;
	entry->next = list;
	head->next = new_first;
	new_first->prev = head;
}

/**
 * list_cut_position - cut a list into two
 * @list: a new list to add all removed entries
 * @head: a list with entries
 * @entry: an entry within head, could be the head itself
 *	and if so we won't cut the list
 *
 * This helper moves the initial part of @head, up to and
 * including @entry, from @head to @list. You should
 * pass on @entry an element you know is on @head. @list
 * should be an empty list or a list you do not care about
 * losing its data.
 *
 */
static inline void list_cut_position(struct list_head *list,
			struct list_head *head, struct list_head *entry)
{
	if (list_empty(head))
	  return;
	if (list_is_singular(head) &&
				(head->next != entry && head != entry))
	  return;
	if (entry == head)
	  INIT_LIST_HEAD(list);
	else
	  __list_cut_position(list, head, entry);
}

/**
 * list_cut_before - cut a list into two, before given entry
 * @list: a new list to add all removed entries
 * @head: a list with entries
 * @entry: an entry within head, could be the head itself
 *
 * This helper moves the initial part of @head, up to but
 * excluding @entry, from @head to @list.  You should pass
 * in @entry an element you know is on @head.  @list should
 * be an empty list or a list you do not care about losing
 * its data.
 * If @entry == @head, all entries on @head are moved to
 * @list.
 */
static inline void list_cut_before(struct list_head *list,
			struct list_head *head,
			struct list_head *entry)
{
	if (head->next == entry) {
		INIT_LIST_HEAD(list);
		return;
	}
	list->next = head->next;
	list->next->prev = list;
	list->prev = entry->prev;
	list->prev->next = list;
	head->next = entry;
	entry->prev = head;
}

static inline void __list_splice(const struct list_head *list,
			struct list_head *prev,
			struct list_head *next)
{
	struct list_head *first = list->next;
	struct list_head *last = list->prev;

	first->prev = prev;
	prev->next = first;

	last->next = next;
	next->prev = last;
}

/**
 * list_splice - join two lists, this is designed for stacks
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 */
static inline void list_splice(const struct list_head *list,
			struct list_head *head)
{
	if (!list_empty(list))
	  __list_splice(list, head, head->next);
}

/**
 * list_splice_tail - join two lists, each list being a queue
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 */
static inline void list_splice_tail(struct list_head *list,
			struct list_head *head)
{
	if (!list_empty(list))
	  __list_splice(list, head->prev, head);
}

/**
 * list_splice_init - join two lists and reinitialise the emptied list.
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 *
 * The list at @list is reinitialised
 */
static inline void list_splice_init(struct list_head *list,
			struct list_head *head)
{
	if (!list_empty(list)) {
		__list_splice(list, head, head->next);
		INIT_LIST_HEAD(list);
	}
}

/**
 * list_splice_tail_init - join two lists and reinitialise the emptied list
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 *
 * Each of the lists is a queue.
 * The list at @list is reinitialised
 */
static inline void list_splice_tail_init(struct list_head *list,
			struct list_head *head)
{
	if (!list_empty(list)) {
		__list_splice(list, head->prev, head);
		INIT_LIST_HEAD(list);
	}
}

/**
 * list_entry - get the struct for this entry
 * @ptr:	the &struct list_head pointer.
 * @type:	the type of the struct this is embedded in.
 * @member:	the name of the list_head within the struct.
 */
#define list_entry(ptr, type, member) \
	container_of(ptr, type, member)

/**
 * list_first_entry - get the first element from a list
 * @ptr:	the list head to take the element from.
 * @type:	the type of the struct this is embedded in.
 * @member:	the name of the list_head within the struct.
 *
 * Note, that list is expected to be not empty.
 */
#define list_first_entry(ptr, type, member) \
	list_entry((ptr)->next, type, member)

/**
 * list_last_entry - get the last element from a list
 * @ptr:	the list head to take the element from.
 * @type:	the type of the struct this is embedded in.
 * @member:	the name of the list_head within the struct.
 *
 * Note, that list is expected to be not empty.
 */
#define list_last_entry(ptr, type, member) \
	list_entry((ptr)->prev, type, member)

/**
 * list_first_entry_or_null - get the first element from a list
 * @ptr:	the list head to take the element from.
 * @type:	the type of the struct this is embedded in.
 * @member:	the name of the list_head within the struct.
 *
 * Note that if the list is empty, it returns NULL.
 */
#define list_first_entry_or_null(ptr, type, member) ({ \
			struct list_head *head__ = (ptr); \
			struct list_head *pos__ = READ_ONCE(head__->next); \
			pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
			})

/**
 * list_next_entry - get the next element in list
 * @pos:	the type * to cursor
 * @member:	the name of the list_head within the struct.
 */
#define list_next_entry(pos, member) \
	list_entry((pos)->member.next, typeof(*(pos)), member)

/**
 * list_prev_entry - get the prev element in list
 * @pos:	the type * to cursor
 * @member:	the name of the list_head within the struct.
 */
#define list_prev_entry(pos, member) \
	list_entry((pos)->member.prev, typeof(*(pos)), member)

/**
 * list_for_each	-	iterate over a list
 * @pos:	the &struct list_head to use as a loop cursor.
 * @head:	the head for your list.
 */
#define list_for_each(pos, head) \
	for (pos = (head)->next; pos != (head); pos = pos->next)

/**
 * list_for_each_prev	-	iterate over a list backwards
 * @pos:	the &struct list_head to use as a loop cursor.
 * @head:	the head for your list.
 */
#define list_for_each_prev(pos, head) \
	for (pos = (head)->prev; pos != (head); pos = pos->prev)

/**
 * list_for_each_safe - iterate over a list safe against removal of list entry
 * @pos:	the &struct list_head to use as a loop cursor.
 * @n:		another &struct list_head to use as temporary storage
 * @head:	the head for your list.
 */
#define list_for_each_safe(pos, n, head) \
	for (pos = (head)->next, n = pos->next; pos != (head); \
				pos = n, n = pos->next)

/**
 * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
 * @pos:	the &struct list_head to use as a loop cursor.
 * @n:		another &struct list_head to use as temporary storage
 * @head:	the head for your list.
 */
#define list_for_each_prev_safe(pos, n, head) \
	for (pos = (head)->prev, n = pos->prev; \
				pos != (head); \
				pos = n, n = pos->prev)

/**
 * list_for_each_entry	-	iterate over list of given type
 * @pos:	the type * to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the list_head within the struct.
 */
#define list_for_each_entry(pos, head, member)				\
	for (pos = list_first_entry(head, typeof(*pos), member);	\
				&pos->member != (head);					\
				pos = list_next_entry(pos, member))

/**
 * list_for_each_entry_reverse - iterate backwards over list of given type.
 * @pos:	the type * to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the list_head within the struct.
 */
#define list_for_each_entry_reverse(pos, head, member)			\
	for (pos = list_last_entry(head, typeof(*pos), member);		\
				&pos->member != (head); 					\
				pos = list_prev_entry(pos, member))

/**
 * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
 * @pos:	the type * to use as a start point
 * @head:	the head of the list
 * @member:	the name of the list_head within the struct.
 *
 * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
 */
#define list_prepare_entry(pos, head, member) \
	((pos) ? : list_entry(head, typeof(*pos), member))

/**
 * list_for_each_entry_continue - continue iteration over list of given type
 * @pos:	the type * to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the list_head within the struct.
 *
 * Continue to iterate over list of given type, continuing after
 * the current position.
 */
#define list_for_each_entry_continue(pos, head, member) 		\
	for (pos = list_next_entry(pos, member);			\
				&pos->member != (head);					\
				pos = list_next_entry(pos, member))

/**
 * list_for_each_entry_continue_reverse - iterate backwards from the given point
 * @pos:	the type * to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the list_head within the struct.
 *
 * Start to iterate over list of given type backwards, continuing after
 * the current position.
 */
#define list_for_each_entry_continue_reverse(pos, head, member)		\
	for (pos = list_prev_entry(pos, member);			\
				&pos->member != (head);					\
				pos = list_prev_entry(pos, member))

/**
 * list_for_each_entry_from - iterate over list of given type from the current point
 * @pos:	the type * to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the list_head within the struct.
 *
 * Iterate over list of given type, continuing from current position.
 */
#define list_for_each_entry_from(pos, head, member) 			\
	for (; &pos->member != (head);					\
				pos = list_next_entry(pos, member))

/**
 * list_for_each_entry_from_reverse - iterate backwards over list of given type
 *                                    from the current point
 * @pos:	the type * to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the list_head within the struct.
 *
 * Iterate backwards over list of given type, continuing from current position.
 */
#define list_for_each_entry_from_reverse(pos, head, member)		\
	for (; &pos->member != (head);					\
				pos = list_prev_entry(pos, member))

/**
 * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
 * @pos:	the type * to use as a loop cursor.
 * @n:		another type * to use as temporary storage
 * @head:	the head for your list.
 * @member:	the name of the list_head within the struct.
 */
#define list_for_each_entry_safe(pos, n, head, member)			\
	for (pos = list_first_entry(head, typeof(*pos), member),	\
				n = list_next_entry(pos, member);			\
				&pos->member != (head); 					\
				pos = n, n = list_next_entry(n, member))

/**
 * list_for_each_entry_safe_continue - continue list iteration safe against removal
 * @pos:	the type * to use as a loop cursor.
 * @n:		another type * to use as temporary storage
 * @head:	the head for your list.
 * @member:	the name of the list_head within the struct.
 *
 * Iterate over list of given type, continuing after current point,
 * safe against removal of list entry.
 */
#define list_for_each_entry_safe_continue(pos, n, head, member) 		\
	for (pos = list_next_entry(pos, member), 				\
				n = list_next_entry(pos, member);				\
				&pos->member != (head);						\
				pos = n, n = list_next_entry(n, member))

/**
 * list_for_each_entry_safe_from - iterate over list from current point safe against removal
 * @pos:	the type * to use as a loop cursor.
 * @n:		another type * to use as temporary storage
 * @head:	the head for your list.
 * @member:	the name of the list_head within the struct.
 *
 * Iterate over list of given type from current point, safe against
 * removal of list entry.
 */
#define list_for_each_entry_safe_from(pos, n, head, member) 			\
	for (n = list_next_entry(pos, member);					\
				&pos->member != (head);						\
				pos = n, n = list_next_entry(n, member))

/**
 * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
 * @pos:	the type * to use as a loop cursor.
 * @n:		another type * to use as temporary storage
 * @head:	the head for your list.
 * @member:	the name of the list_head within the struct.
 *
 * Iterate backwards over list of given type, safe against removal
 * of list entry.
 */
#define list_for_each_entry_safe_reverse(pos, n, head, member)		\
	for (pos = list_last_entry(head, typeof(*pos), member),		\
				n = list_prev_entry(pos, member);			\
				&pos->member != (head); 					\
				pos = n, n = list_prev_entry(n, member))

/**
 * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
 * @pos:	the loop cursor used in the list_for_each_entry_safe loop
 * @n:		temporary storage used in list_for_each_entry_safe
 * @member:	the name of the list_head within the struct.
 *
 * list_safe_reset_next is not safe to use in general if the list may be
 * modified concurrently (eg. the lock is dropped in the loop body). An
 * exception to this is if the cursor element (pos) is pinned in the list,
 * and list_safe_reset_next is called after re-taking the lock and before
 * completing the current iteration of the loop body.
 */
#define list_safe_reset_next(pos, n, member)				\
	n = list_next_entry(pos, member)

/*
 * Double linked lists with a single pointer list head.
 * Mostly useful for hash tables where the two pointer list head is
 * too wasteful.
 * You lose the ability to access the tail in O(1).
 */

#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
	h->next = NULL;
	h->pprev = NULL;
}

static inline int hlist_unhashed(const struct hlist_node *h)
{
	return !h->pprev;
}

static inline int hlist_empty(const struct hlist_head *h)
{
	return !READ_ONCE(h->first);
}

static inline void __hlist_del(struct hlist_node *n)
{
	struct hlist_node *next = n->next;
	struct hlist_node **pprev = n->pprev;

	WRITE_ONCE(*pprev, next);
	if (next)
	  next->pprev = pprev;
}

static inline void hlist_del(struct hlist_node *n)
{
	__hlist_del(n);
	n->next = LIST_POISON1;
	n->pprev = LIST_POISON2;
}

static inline void hlist_del_init(struct hlist_node *n)
{
	if (!hlist_unhashed(n)) {
		__hlist_del(n);
		INIT_HLIST_NODE(n);
	}
}

static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
	struct hlist_node *first = h->first;
	n->next = first;
	if (first)
	  first->pprev = &n->next;
	WRITE_ONCE(h->first, n);
	n->pprev = &h->first;
}

/* next must be != NULL */
static inline void hlist_add_before(struct hlist_node *n,
			struct hlist_node *next)
{
	n->pprev = next->pprev;
	n->next = next;
	next->pprev = &n->next;
	WRITE_ONCE(*(n->pprev), n);
}

static inline void hlist_add_behind(struct hlist_node *n,
			struct hlist_node *prev)
{
	n->next = prev->next;
	WRITE_ONCE(prev->next, n);
	n->pprev = &prev->next;

	if (n->next)
	  n->next->pprev  = &n->next;
}

/* after that we'll appear to be on some hlist and hlist_del will work */
static inline void hlist_add_fake(struct hlist_node *n)
{
	n->pprev = &n->next;
}

static inline bool hlist_fake(struct hlist_node *h)
{
	return h->pprev == &h->next;
}

/*
 * Check whether the node is the only node of the head without
 * accessing head:
 */
static inline bool
hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h)
{
	return !n->next && n->pprev == &h->first;
}

/*
 * Move a list from one list head to another. Fixup the pprev
 * reference of the first entry if it exists.
 */
static inline void hlist_move_list(struct hlist_head *old,
			struct hlist_head *new)
{
	new->first = old->first;
	if (new->first)
	  new->first->pprev = &new->first;
	old->first = NULL;
}

#define hlist_entry(ptr, type, member) container_of(ptr,type,member)

#define hlist_for_each(pos, head) \
	for (pos = (head)->first; pos ; pos = pos->next)

#define hlist_for_each_safe(pos, n, head) \
	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
				pos = n)

#define hlist_entry_safe(ptr, type, member) \
	({ typeof(ptr) ____ptr = (ptr); \
	 ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
	 })

/**
 * hlist_for_each_entry	- iterate over list of given type
 * @pos:	the type * to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the hlist_node within the struct.
 */
#define hlist_for_each_entry(pos, head, member)				\
	for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
				pos;							\
				pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))

/**
 * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
 * @pos:	the type * to use as a loop cursor.
 * @member:	the name of the hlist_node within the struct.
 */
#define hlist_for_each_entry_continue(pos, member)			\
	for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\
				pos;							\
				pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))

/**
 * hlist_for_each_entry_from - iterate over a hlist continuing from current point
 * @pos:	the type * to use as a loop cursor.
 * @member:	the name of the hlist_node within the struct.
 */
#define hlist_for_each_entry_from(pos, member)				\
	for (; pos;							\
				pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))

/**
 * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
 * @pos:	the type * to use as a loop cursor.
 * @n:		another &struct hlist_node to use as temporary storage
 * @head:	the head for your list.
 * @member:	the name of the hlist_node within the struct.
 */
#define hlist_for_each_entry_safe(pos, n, head, member) 		\
	for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
				pos && ({ n = pos->member.next; 1; });			\
				pos = hlist_entry_safe(n, typeof(*pos), member))

#endif
main.c文件
#include <stdio.h>
#include "list.h"

/*
 * 1. 由通用节点指针获取包含它的外部具体节点指针的宏:
 *      list_entry(ptr, type, member);  这是对 container_of 的封装
 *      container_of(ptr, type, member);
 * 2. 静态初始化链表宏:
 *      LIST_HEAD(name)   name 就是链表名
 * 3. 动态初始化链表 list:
 *      void INIT_LIST_HEAD(struct list_head *list);
 * 4. 链表 head 头插入 new :
 *      void list_add(struct list_head *new, struct list_head *head);
 * 5. 链表 head 尾插入 new :
 *      void list_add_tail(struct list_head *new, struct list_head *head);
 * 6. 从链表中删除入口 entry :
 *      void list_del(struct list_head *entry);
 * 7. 老入口 old 替换为新入口 new:
 *      void list_replace(struct list_head *old, struct list_head *new);
 * 8. 将一个节点 list 移到一个链表 head 头:
 *      void list_move(struct list_head *list, struct list_head *head);
 * 9. 将一个节点 list 移到一个链表 head 尾:
 *      void list_move_tail(struct list_head *list, struct list_head *head);
 * 10.判断入口 list 是否是链表 head 的最后一个入口:
 *      int list_is_last(const struct list_head *list, 
 *                       const struct list_head *head);
 * 11.判断链表是否为空:
 *      int list_empty(const struct list_head *head);
 * 12.获取链表的首节点宏:
 *      list_first_entry(ptr, type, member);
 * 13.获取链表的尾节点宏:
 *      list_last_entry(ptr, type, member);
 * 14.获取下一个节点宏:
 *      list_next_entry(pos, member);
 * 15.获取前一个节点宏:
 *      list_prev_entry(pos, member);
 * 16.遍历链表 head,pos 是用于遍历链表的通用节点指针:
 *      list_for_each(pos, head);
 * 17.向前遍历链表 head,pos 是用于遍历链表的通用节点指针:
 *      list_for_each_prev(pos, head);
 * 18.遍历链表 head 的每个入口,pos 是用于遍历链表的具体节点指针:
 *      list_for_each_entry(pos, head, member);
 * 19.向前遍历链表 head,pos 是用于遍历链表的具体节点指针:
 *      list_for_each_entry_reverse(pos, head, member);
 */

/* 使用 Linux 链表可以实现对任意类型的数据放入链表进行管理 */

/* 具体节点,包含通用节点,位置没有要求 */
typedef struct {
    int data;
    struct list_head list;
} int_t;

int main(void)
{
    int_t data[] = {{1}, {2}, {3}, {4}, {5}};
    struct list_head list, *pos;
    int i;
    int_t *pnode;

    /* 初始化链表 */
    INIT_LIST_HEAD(&list);
    /* 插入到链表 */
    for (i = 0; i < 5; i++) {
	//list_add(&data[i].list, &list);         /* 头部插入 */
	list_add_tail(&data[i].list, &list);    /* 尾部插入 */
    }

    /* 遍历链表,打印每个节点的值 */
    printf("通过通用节点遍历:");
    list_for_each(pos, &list) {
	pnode = list_entry(pos, int_t, list);
	printf("%d ", pnode->data);
    }
    putchar('\n');

    /* 删除首节点 */
    list_del(list.next);

    printf("通过具体节点遍历:");
    list_for_each_entry(pnode, &list, list) {
	printf("%d ", pnode->data);
    }
    putchar('\n');

    return 0;
}

09_空递增栈

stack.h文件
#ifndef _STACK_H
#define _STACK_H

// 栈的大小
#define STACK_SIZE  100

// 元素类型别名
typedef int elem_t;

// 空递增栈类型
typedef struct {
    elem_t data[STACK_SIZE];
    int top;
} stack_t;

// 初始化栈
void stack_init(stack_t *pstack);

// 入栈
int stack_push(stack_t *pstack, elem_t *pe);

// 出栈
int stack_pop(stack_t *pstack, elem_t *pe);

// 判栈空
static inline int stack_is_empty(stack_t *pstack)
{
    return pstack->top == 0;
}

// 判栈满
static inline int stack_is_full(stack_t *pstack)
{
    return pstack->top == STACK_SIZE;
}


#endif
stack.c文件
#include <string.h>
#include "stack.h"

// 初始化栈
void stack_init(stack_t *pstack)
{
    pstack->top = 0;
}

// 入栈:成功返回 0,失败返回 -1
int stack_push(stack_t *pstack, elem_t *pe)
{
    // 满栈不能入栈
    if (stack_is_full(pstack)) return -1;

    // 先放数据
    memcpy(pstack->data + pstack->top, pe, sizeof (elem_t));
    // 再 top 递增
    pstack->top++;

    return 0; 
}

// 出栈
int stack_pop(stack_t *pstack, elem_t *pe)
{
    // 空栈不能出栈
    if (stack_is_empty(pstack)) return -1;
    
    // 先 top 递减
    pstack->top--;
    // 再取数据 
    memcpy(pe, pstack->data + pstack->top, sizeof (elem_t));

    return 0;
}
main.c文件
#include <stdio.h>
#include "stack.h"

void print_stack(stack_t *pstack)
{
    for (int i = 0; i < pstack->top; i++) {
	printf("%d ", pstack->data[i]);
    }
}

int main(void)
{
    elem_t data[] = {3, 1, 6, 2, 4}, e;
    stack_t stack1;

    // 初始化栈
    stack_init(&stack1);

    // 入栈
    for (int i = 0; i < 5; i++) {
	stack_push(&stack1, data + i);
    }

    // 遍历栈
    printf("遍历栈\n");
    print_stack(&stack1);
    printf("\n");

    // 出栈
    stack_pop(&stack1, &e);
    printf("出栈:%d\n", e);
    stack_pop(&stack1, &e);
    printf("出栈:%d\n", e);
    stack_pop(&stack1, &e);
    printf("出栈:%d\n", e);
    stack_pop(&stack1, &e);
    printf("出栈:%d\n", e);
    stack_pop(&stack1, &e);
    printf("出栈:%d\n", e);
    if (-1 == stack_pop(&stack1, &e)) {
	printf("出栈失败\n");
    } else {
	printf("出栈:%d\n", e);
    }

    return 0;
}

10_链栈

stack.h文件
#ifndef _STACK_H
#define _STACK_H

// 元素类型
typedef int elem_t;

// 节点类型
typedef struct __node {
    elem_t data;
    struct __node *next;
} node_t;

// 初始化
void stack_init(node_t *pstack);

// 入栈
int stack_push(node_t *pstack, elem_t *pe);

// 出栈
int stack_pop(node_t *pstack, elem_t *pe);

// 判栈空
static inline int stack_is_empty(node_t *pstack)
{
    return pstack->next == NULL;
}

#endif
stack.c文件
#include <stdlib.h>
#include <string.h>
#include "stack.h"

// 初始化
void stack_init(node_t *pstack)
{
    pstack->next = NULL;
}

// 入栈
int stack_push(node_t *pstack, elem_t *pe)
{
    node_t *pnode;

    // 分配内存
    pnode = malloc(sizeof (node_t));
    if (!pnode) return -1;
    // 复制数据
    memcpy(&pnode->data, pe, sizeof (elem_t));
    // 从头节点插入
    pnode->next = pstack->next;
    pstack->next = pnode;

    return 0;
}

// 出栈
int stack_pop(node_t *pstack, elem_t *pe)
{
    node_t *pdel;

    // 栈空不能出栈
    if (stack_is_empty(pstack)) return -1;

    pdel = pstack->next;
    // 保存数据
    memcpy(pe, &pdel->data, sizeof (elem_t)); 
    // 从头节点删除
    pstack->next = pdel->next;
    // 释放内存
    free(pdel);

    return 0;
}
main.c文件
#include <stdio.h>
#include "stack.h"

// 遍历栈
void print_stack(node_t *psatck)
{
    node_t *pnode = psatck->next;

    while (pnode) {
	printf("%d ", pnode->data);
	pnode = pnode->next;
    }
}

int main(void)
{
    elem_t data[] = {1, 2, 3, 4, 5}, e;
    node_t stack1;

    // 初始化
    stack_init(&stack1);

    // 入栈
    for (int i = 0; i < 5; i++) {
	stack_push(&stack1, data + i);
    }

    // 打印栈
    printf("遍历栈:\n");
    print_stack(&stack1);
    putchar('\n');
    
    // 出栈
    stack_pop(&stack1, &e);
    printf("出栈:%d\n", e);

    // 打印栈
    printf("遍历栈:\n");
    print_stack(&stack1);
    putchar('\n');

    return 0;
}

11_顺序队

queue.h文件
#ifndef _QUEUE_H
#define _QUEUE_H

// 顺序队大小
#define QUEUE_SIZE 100

// 元素类型
typedef int elem_t;

// 顺序队类型
typedef struct {
    elem_t data[QUEUE_SIZE];
    int front, rear;
} queue_t;

// 初始化顺序队
void queue_init(queue_t *pq);

// 入队
int enqueue(queue_t *pq, elem_t *pe);

// 出队
int dequeue(queue_t *pq, elem_t *pe);

// 判队空
static inline int queue_is_empty(queue_t *pq)
{
    return pq->front == pq->rear;
}

// 判队满
static inline int queue_is_full(queue_t *pq)
{
    return (pq->rear + 1) % QUEUE_SIZE == pq->front;
}

#endif
queue.c文件
#include <string.h>
#include "queue.h"

// 初始化顺序队
void queue_init(queue_t *pq)
{
    pq->front = pq->rear = 0;
}

// 入队
int enqueue(queue_t *pq, elem_t *pe)
{
    // 队列满则不能入队
    if (queue_is_full(pq)) return -1;

    // 入队是从 rear 处入队的,rear 指向空位置
    memcpy(&pq->data[pq->rear], pe, sizeof (elem_t));
    // 队尾指针递增
    pq->rear = (pq->rear + 1) % QUEUE_SIZE;
    // 或者使用 if 判断也行
    //if (++pq->rear >= QUEUE_SIZE) pq->rear = 0;

    return 0;
}

// 出队
int dequeue(queue_t *pq, elem_t *pe)
{
    // 队空不能出队
    if (queue_is_empty(pq)) return -1;

    // 出队是从队头出队,front 指向的是数据
    if (pe) {
	memcpy(pe, pq->data + pq->front, sizeof (elem_t));
    }

    // 队头指针递增
    pq->front = (pq->front + 1) % QUEUE_SIZE;

    return 0;
}
main.c文件
#include <stdio.h>
#include "queue.h"

int main(void)
{
    queue_t queue1;
    elem_t data[] = {1, 2, 3, 4, 5}, e;

    // 初始化
    queue_init(&queue1);

    // 入队
    for (int i = 0; i < 5; i++) {
	enqueue(&queue1, data + i);
    }

    // 出队
    dequeue(&queue1, &e);
    printf("出队元素:%d\n", e);
    dequeue(&queue1, &e);
    printf("出队元素:%d\n", e);
    dequeue(&queue1, &e);
    printf("出队元素:%d\n", e);
    dequeue(&queue1, &e);
    printf("出队元素:%d\n", e);
    dequeue(&queue1, &e);
    printf("出队元素:%d\n", e);

    // 判队空
    if (queue_is_empty(&queue1)) {
	printf("队列为空\n");
    } else {
	printf("队列非空\n");
    }

    return 0;
}

12_链队

queue.h文件
#ifndef _QUEUE_H
#define _QUEUE_H

// 元素类型
typedef int elem_t;

// 节点类型
typedef struct _node {
    elem_t data;
    struct _node *next;
} node_t;

// 链队类型
typedef struct {
    node_t head;
    node_t *rear;
} queue_t; 

// 初始化链队
void queue_init(queue_t *pq);

// 入队
int enqueue(queue_t *pq, elem_t *pe);

// 出队
int dequeue(queue_t *pq, elem_t *pe);

// 判队空
int queue_is_empty(queue_t *pq);

#endif
queue.c文件
#include "stdlib.h"
#include "string.h"
#include "queue.h"

// 初始化链队
void queue_init(queue_t *pq)
{
    pq->head.next = NULL;
    pq->rear = &pq->head;
}

// 入队
int enqueue(queue_t *pq, elem_t *pe)
{
    node_t *pnew;

    if (!pq || !pe) return -1;

    // 从队尾(链表尾)入队(插入)
    // 为新节点分配内存
    pnew = malloc(sizeof (node_t));
    // 复制数据
    memcpy(&pnew->data, pe, sizeof (elem_t));
    // 链入尾部
    pnew->next = NULL;
    pq->rear->next = pnew;
    // rear 指向新的队尾元素
    pq->rear = pnew;

    return 0;
}

// 出队
int dequeue(queue_t *pq, elem_t *pe)
{
    node_t *pdel;

    // 非法队列指针,或队列为空都不能出队
    if (!pq || queue_is_empty(pq)) return -1;

    // 从队头(链表头)出队(删除)
    pdel = pq->head.next;
    // 复制数据
    if (pe) { 
	memcpy(pe, &pq->head.next->data, sizeof (elem_t));
    }
    // 从链表头删除
    pq->head.next = pdel->next;
    // 只有一个节点时,出队后队列为空,需要将 rear 指向 head
    if (pdel->next == NULL) pq->rear = &pq->head;
    // 释放内存
    free(pdel);

    return 0;
}

// 判队空
int queue_is_empty(queue_t *pq)
{
    return pq->rear == &pq->head;
}
main.c文件
#include <stdio.h>
#include "queue.h"

int main(void)
{
    queue_t queue1;
    elem_t data[] = {1, 2, 3, 4, 5}, e;

    // 初始化
    queue_init(&queue1);

    // 入队
    for (int i = 0; i < 5; i++) {
	enqueue(&queue1, data + i);
    }

    // 出队
    dequeue(&queue1, &e);
    printf("出队元素:%d\n", e);
    dequeue(&queue1, &e);
    printf("出队元素:%d\n", e);
    dequeue(&queue1, &e);
    printf("出队元素:%d\n", e);
    dequeue(&queue1, &e);
    printf("出队元素:%d\n", e);
    dequeue(&queue1, &e);
    printf("出队元素:%d\n", e);

    // 判队空
    if (queue_is_empty(&queue1)) {
	printf("队列为空\n");
    } else {
	printf("队列非空\n");
    }

    return 0;
}

13_顺序二叉排序树

btree.h文件
#ifndef _BTREE_H
#define _BTREE_H

#define BTREE_SIZE 128

// 元素类型
typedef int elem_t;

// 二叉排序树类型
typedef struct {
    elem_t data[BTREE_SIZE];  // 数组存放树的节点值
    int flag[BTREE_SIZE];     // 标志存放对应节点是否存在:1 存在,0 不存在
    int count;                // 节点数
} btree_t;

// 初始化
void btree_init(btree_t *pbt);

// 插入元素
int btree_insert(btree_t *pbt, elem_t *pe);

// 查找元素
int btree_search(btree_t *pbt, elem_t *pe);

#endif
btree.c文件
#include <string.h>
#include <stdio.h>
#include "btree.h"

// 初始化
void btree_init(btree_t *pbt)
{
    // flag 清 0
    memset(pbt->flag, 0, sizeof (pbt->flag[0]) * BTREE_SIZE);
    // count 清 0
    pbt->count = 0;
}

// 插入元素
int btree_insert(btree_t *pbt, elem_t *pe)
{
    int index = 1;

    // 非空树,找到插入位置
    while (index < BTREE_SIZE) {
	if (pbt->flag[index]) { // 当前位置有元素
	    // 在左子树
	    if (*pe < pbt->data[index]) {
		index = 2 * index;
	    } else {  // 在右子树
		index = 2 * index + 1;
	    }
	} else {  // 当前位置不存在元素,直接放入
	    pbt->data[index] = *pe;
	    pbt->flag[index] = 1;
	    pbt->count++;
	    return 0;  // 元素已放入,可以返回了
	}
    }

    // 循环由于 index >= BTREE_SIZE 则插入失败
    return -1;
}

// 查找元素,返回它的编号,未找到返回 -1
int btree_search(btree_t *pbt, elem_t *pe)
{
    int index = 1;

    // 未超出范围,并且树未搜完
    while (index < BTREE_SIZE && pbt->flag[index]) {
	if (*pe == pbt->data[index]) {  // 找到了
	    return index;
	} else if (*pe < pbt->data[index]) {  // 左子树
	    index *= 2;
	} else {  // 右子树
	    index = index * 2 + 1;
	}
    }

    return -1;
}
main.c文件
#include <stdio.h>
#include "btree.h"

#define LENGTHOF(array) (sizeof (array) / sizeof (array[0]))

int main(void)
{
    btree_t tree1;
    elem_t data[] = {10, 4, 12, 9, 8, 16}, e;
    int index;

    // 初始化
    btree_init(&tree1);

    // 插入元素
    for (int i = 0; i < LENGTHOF(data); i++) {
	btree_insert(&tree1, data + i);
    }

    for (int i = 1; i < 20; i++) {
	if (tree1.flag[i]) {
	    printf("%d(%d) = %d\n", i, tree1.flag[i], tree1.data[i]);
	} else {
	    printf("%d(%d) = \n", i, tree1.flag[i]);
	}
    }

    // 查找元素
    e = 16;
    if (-1 == (index = btree_search(&tree1, &e))) {
	printf("未找到元素 %d\n", e);
    } else {
	printf("找到元素 %d,位置 %d\n", e, index);
    }
    e = 17;
    if (-1 == (index = btree_search(&tree1, &e))) {
	printf("未找到元素 %d\n", e);
    } else {
	printf("找到元素 %d,位置 %d\n", e, index);
    }

    return 0;
}

14_链式二叉排序树

btree.h文件
#ifndef _BTREE_H
#define _BTREE_H

// 元素类型
typedef int elem_t;

// 节点类型
typedef struct _node {
    elem_t data;
    struct _node *parent, *lchild, *rchild;
} node_t;

// 二叉树类型
typedef struct {
    node_t *root;   // 指向二叉树的根节点
    int count;
} btree_t;

// 初始化
void btree_init(btree_t *pbt);

// 插入元素
int btree_insert(btree_t *pbt, elem_t *pe);

// 搜索元素
node_t *btree_search(btree_t *pbt, elem_t *pe);

// 先根遍历
void _pre_order(node_t *pn);

// 中根遍历
void _in_order(node_t *pn);

// 后根遍历
void _post_order(node_t *pn);

// 遍历二叉树
void btree_travel(btree_t *pbt, int order);

// 删除元素
int btree_delete(btree_t *pbt, elem_t *pe);

#endif
btree.c文件
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "btree.h"

// 初始化
void btree_init(btree_t *pbt)
{
    pbt->root = NULL;
    pbt->count = 0;
}

// 插入元素
int btree_insert(btree_t *pbt, elem_t *pe)
{
    node_t *pnew, *pnode, *parent;

    // 分配节点内存
    pnew = malloc(sizeof (node_t));
    if (!pnew) return -1;   // 未分配到内存

    // 复制数据,指针的初始化
    memcpy(&pnew->data, pe, sizeof (elem_t));
    pnew->parent = pnew->lchild = pnew->rchild = NULL;

    // 空树,直接插入到根
    if (!pbt->root) {
	pbt->root = pnew;
	pbt->count++;
	return 0;
    }

    // 查找插入点
    pnode = pbt->root;   // 从根节点开始比对
    while (pnode) {
	parent = pnode;
	if (pnew->data < pnode->data) {  // 左子树查找位置
	    pnode = pnode->lchild;
	} else {  // 右子树查找位置
	    pnode = pnode->rchild;
	}
    }
    // 循环结束,pnode 指向 NULL,pnew 成为 parent 的左或右孩子
    if (pnew->data < parent->data) {
	parent->lchild = pnew;
    } else {
	parent->rchild = pnew;
    }
    pnew->parent = parent;
    pbt->count++;

    return 0;
}

// 搜索元素,找到返回节点指针,未找到返回 NULL
node_t *btree_search(btree_t *pbt, elem_t *pe)
{
    node_t *pnode = pbt->root;

    while (pnode) {
	if (*pe == pnode->data) {   // 找到了
	    return pnode;
	} else if (*pe < pnode->data) {  // 左子树
	    pnode = pnode->lchild;
	} else {  // 右子树
	    pnode = pnode->rchild;
	}
    }

    return NULL;
}

// 先根遍历
void _pre_order(node_t *pn)
{
    if (pn) {
	printf("%d ", pn->data); // 先访问根节点
	_pre_order(pn->lchild);  // 先根遍历左孩子
	_pre_order(pn->rchild);  // 先根遍历右孩子
    }
}

// 中根遍历
void _in_order(node_t *pn)
{
    if (pn) {
	_in_order(pn->lchild);    // 中根遍历左孩子
	printf("%d ", pn->data);  // 再访问根节点
	_in_order(pn->rchild);    // 中根遍历右孩子
    }
}

// 后根遍历
void _post_order(node_t *pn)
{
    if (pn) {
	_post_order(pn->lchild);    // 后根遍历左孩子
	_post_order(pn->rchild);    // 后根遍历右孩子
	printf("%d ", pn->data);    // 最后再访问根节点
    }
}

// 遍历二叉树
// order:0 先根,1 中根,2 后根
void btree_travel(btree_t *pbt, int order)
{
    if (!pbt)  return;

    if (0 == order) {
	_pre_order(pbt->root);
    } else if (1 == order) {
	_in_order(pbt->root);
    } else if (2 == order) {
	_post_order(pbt->root);
    }
}

// 删除元素
int btree_delete(btree_t *pbt, elem_t *pe)
{
    node_t *pnode, *pdel;

    // 找到待删除的节点
    pnode = pbt->root;
    while (pnode) {
	if (pnode->data == *pe) {
	    break;
	} else if (*pe < pnode->data) {
	    pnode = pnode->lchild;
	} else {
	    pnode = pnode->rchild;
	}
    }
    // 未找到节点,则删除失败
    if (!pnode) return -1; 
    pdel = pnode;
    // 如果节点有两个孩子,则从左子树中找到最大节点,与之交换值
    // 将这种情况转换成只有一个孩子或无孩子的情况
    if (pnode->lchild && pnode->rchild) {
	elem_t tmp;
	pnode = pnode->lchild;   // 从左子树根节点开始
	while (pnode->rchild) {  // 只查找右子树
	    pnode = pnode->rchild;
	}
	// 交换两个节点的值
	memcpy(&tmp, &pdel->data, sizeof (elem_t));
	memcpy(&pdel->data, &pnode->data, sizeof (elem_t));
	memcpy(&pnode->data, &tmp, sizeof (elem_t));
	pdel = pnode;
    }

    // 如果节点只有一个孩子,直接将这个孩子替代它
    node_t *parent = pdel->parent;
    node_t *child = pdel->lchild ? pdel->lchild : pdel->rchild;
    if (parent) {   // 不是根节点
	if (pdel->lchild || pdel->rchild) {  // 只有一个节点
	    if (pdel == parent->lchild) {
		parent->lchild = child;
	    } else {
		parent->rchild = child;
	    } 
	    child->parent = parent;
	} else {  // 如果节点是叶子,直接删除
	    if (pdel == parent->lchild) {
		parent->lchild = NULL;
	    } else {
		parent->rchild = NULL;
	    }
	}
    } else {  // 是根节点
	if (pdel->lchild || pdel->rchild) {
	    child->parent = NULL;
	    pbt->root = child;
	} else {  // 是叶子
	    pbt->root = NULL;
	}
    }
    free(pdel);
    pbt->count--;

    return 0;
}
main.c文件
#include <stdio.h>
#include "btree.h"

int main(void)
{
    btree_t tree1;
    elem_t data[] = {20, 12, 8, 11, 9, 17, 14, 25, 30}, e;
    node_t *pnode;

    // 初始化
    btree_init(&tree1);

    // 插入元素
    for (int i = 0; i < 9; i++) {
	btree_insert(&tree1, data + i);
    }

    // 中根遍历
    printf("中根遍历:");
    btree_travel(&tree1, 1);
    printf("\n");

    // 删除元素
    e = 12;
    if (-1 == btree_delete(&tree1, &e)) {
	printf("删除 %d 失败\n", e);
    } else {
	printf("删除 %d 成功\n", e);
    }
    // 中根遍历
    printf("中根遍历:");
    btree_travel(&tree1, 1);
    printf("\n");

    e = 20;
    if (-1 == btree_delete(&tree1, &e)) {
	printf("删除 %d 失败\n", e);
    } else {
	printf("删除 %d 成功\n", e);
    }
    // 中根遍历
    printf("中根遍历:");
    btree_travel(&tree1, 1);
    printf("\n");

    return 0;
}

15_顺序查找

main.c文件
#include <stdio.h>

#define LENGTHOF(array)  (sizeof (array) / sizeof ((array)[0]))

// 顺序查找的时间复杂度是 O(n)
// 注意 data 不是数组,而是指针。在函数参数中数组退化为指针
// 在长度为 length 的 data 数组中查找关键字 key
int search(int data[], int length, int key)
{
    //printf("LENGTHOF(data) = %d\n", LENGTHOF(data));
    //for (int i = 0; i < LENGTHOF(data); i++) {   // 错误的求长度方法
    for (int i = 0; i < length; i++) {
	if (data[i] == key) return i;
    }

    return -1;
}

int main(void)
{
    int data[] = {5, 2, 4, 9, 1, 3};
    int index;

    index = search(data, LENGTHOF(data), 9);
    printf("index = %d\n", index);

    return 0;
}

16_折半查找

main.c文件
#include <stdio.h>

#define LENGTHOF(array) (sizeof (array) / sizeof ((array)[0]))

// 折半查找的时间复杂度是 O(log(2)n)
// 折半查找的前提是数据以排好序,并且只能对数组进行折半查找
int search(int data[], int length, int key)
{
    int start = 0, end = length - 1, mid;

    while (start <= end) {
	mid = (start + end) / 2;  // 中间位置
	if (data[mid] == key) {
	    return mid;
	} else if (key > data[mid]) {
	    start = mid + 1;
	} else {
	    end = mid - 1;
	}
    }

    return -1;
}


int main(void)
{
    int data[] = {2, 5, 8, 9, 10, 20, 32};
    int index;

    index = search(data, LENGTHOF(data), 10);
    printf("index = %d\n", index);

    index = search(data, LENGTHOF(data), 40);
    printf("index = %d\n", index);

    return 0;
}

17_冒泡排序

main.c文件
#include <stdio.h>

#define LENGTHOF(array)  (sizeof (array) / sizeof ((array)[0]))

void sort(int data[], int length)
{
    // j 表示已排序的元素个数
    for (int j = 0; j < length -1; j++) {
	// 一趟排序,i 是当前元素索引
	for (int i = 0; i < length - 1 - j; i++) {
	    if (data[i] > data[i + 1]) {  // 逆序则交换
		int t = data[i];
		data[i] = data[i + 1];
		data[i + 1] = t;
	    }
	}
    }
}

void print_array(int data[], int length)
{
    for (int i = 0; i < length; i++) {
	printf("%d ", data[i]);
    }
    printf("\n");
}

int main(void)
{
    int data[] = {5, 3, 1, 2, 4};

    sort(data, LENGTHOF(data));

    print_array(data, LENGTHOF(data));

    return 0;
}

18_简单选择排序

main.c文件
#include <stdio.h>

#define LENGTHOF(array)  (sizeof (array) / sizeof ((array)[0]))

void sort(int data[], int length)
{
    int j;

    // i 表示已排好序的元素个数
    for (int i = 0; i < length - 1; i++) {
	int max_index = 0;  // 假定 0 号元素最大
	for (j = 1; j < length - i; j++) {
	    if (data[max_index] < data[j]) {
		max_index = j;
	    }
	}
	// 交换最大元素与最后元素
	int t = data[max_index];
	data[max_index] = data[j - 1];
	data[j - 1] = t;
    }
}

void print_array(int data[], int length)
{
    for (int i = 0; i < length; i++) {
	printf("%d ", data[i]);
    }
    printf("\n");
}

int main(void)
{
    int data[] = {5, 3, 1, 2, 4};

    sort(data, LENGTHOF(data));

    print_array(data, LENGTHOF(data));

    return 0;
}

19_插入排序

main.c文件
#include <stdio.h>

#define LENGTHOF(array)  (sizeof (array) / sizeof ((array)[0]))

void sort(int data[], int length)
{
    int j;

    // i 是待插入元素的索引号
    // 默认 0 元素是排好序的,从 1 元素开始插入
    for (int i = 1; i < length; i++) {
	// 0 ~ i-1 之间是已排好序的
	int t = data[i];   // 保存要插入的元素
	// 在 0 ~ i-1 范围内,从后往前逐个比较
	for (j = i - 1; j >= 0; j--) {
	    // 排好的元素比待排元素大,则后移
	    if (data[j] > t) {
		data[j + 1] = data[j];
	    } else break;   // 否则停止比较
	}
	// 循环结束时,j 元素比待插入小,因此插入其后
	data[j + 1] = t;
    }
}

void print_array(int data[], int length)
{
    for (int i = 0; i < length; i++) {
	printf("%d ", data[i]);
    }
    printf("\n");
}

int main(void)
{
    int data[] = {5, 3, 1, 2, 4};

    sort(data, LENGTHOF(data));

    print_array(data, LENGTHOF(data));

    return 0;
}

高级c练习:

指针

  1. 编写一个程序实现功能:将字符串”Computer Science”赋给一个字符数组,然后从第一个字母开始间隔的输出该字符串,用指针完成。

#include <stdio.h>

int main(void)
{
    char ch[] = "Computer Science";
    char *p = ch;

    for(int i = 0; i < sizeof(ch); i += 2) {
        printf("%c ",*(p+i));
    }

    printf("\n");

    return 0;
}
  1. 用指针将整型组s[8]={1,2,3,4,5,6,7,8}中的值逆序存放。

#include <stdio.h>

void printf_data(int *data);

int length;	//统计数组元素个数

int main(void)
{
    int data[] = {1,2,3,4,5,6,7,8};
    int *front,*tail;

    //统计数组元素个数
    length = sizeof(data) / sizeof(data[0]);

    front = data;   //等价于 front = &data[0];
    tail = &data[length-1];

    //打印逆序前的数组
    printf_data(data);

    for(int i = 0; i < length / 2; i++) {
        int temp = *(front+i);
        *(front+i) = *(tail-i);
        *(tail- i) = temp;
    }

    //打印逆序后的数组
    printf_data(data);

    return 0;
}

//统计数组元素个数
void printf_data(int *data)
{
    for(int i = 0; i < length; i++) {
        printf("%d ",data[i]);
    }
    printf("\n");
}
  1. 编写一个程序实现功能:将两个字符串合并为一个字符串并且输出,用指针实现。

char str1[20]={“Hello ”}, str2[20]={“World ”};

#include <stdio.h>
#include <string.h>

int main(void)
{
    int i=0,j=0;
    char str1[20]={"Hello "},str2[20]={"World!"},str3[20];
    char *p1=str1,*p2=str2,*p3=str3;

    //把 str1 的字符串赋值给 str3
    while(str1[i] != '\0'){
        *(p3+i) = *(p1+i);
        i++;
    }

    //把 str2 的字符串赋值给 str3
    while(str2[j] != '\0'){
        *(p3+i) = *(p2+j);
        i++;
        j++;
    }

    //给str3最后一个字符赋值 '\0'
    *(p3+i) = '\0';

    //打印 str3
    for(i = 0; i < strlen(str3); i++){
        printf("%c",*(p3+i));
    }

    printf("\n");

    return 0;
}
==================================
#include <stdio.h>
#include <string.h>

int main(void)
{
	char str1[10] = {"hello "};
	char str2[10] = {"world"};

	char *p = str1 + strlen(str1);
	char *q = str2;

	int size = sizeof str1;

	int available = size - strlen(str1) - 1;
	while(available-- > 0)
		*p++ = *q++;

	printf("%s\n", str1);

	return 0;
}
  1. 编写一个程序实现以下功能:用指针数组处理一个二维数组,求出二维数组所有元素的和。

int array[3][4]={ {7, 10, -2, 3},

{14, 30, 6, -15},

{0, 5, 27, -7} };

#include <stdio.h>

int main(void)
{
    int i,j,sum = 0;
    int array[3][4]={ {7,  10, -2,  3},
                    {14, 30,  6, -15},
                    {0,  5,  27, -7} };
	/**************************************
	   p[0] --> array[0]:{7, 10, -2, 3}
	   p[1] --> array[1]:{14, 30, 6, -15}
	   p[2] --> array[2]:{0, 5, 27, -7}
	***************************************/
    int (*p[3])[4] = {&array[0],&array[1],&array[2]};

    for(i; i<3; i++){
        for(j; j<4; j++){
            sum += (*p[i])[j];
        }
    }

    printf("%d\n",sum);

    return 0;
}
  1. 已知数组a[10]和b[10]中元素的值递增有序,用指针实现将两个数组中的元素按递增的顺序输出。

#include <stdio.h>

int main(void)
{
    int i,j,k=0;
    int a[6] = {1,14,22,34,88},b[5] = {2,23,45,78,99};
    int *p = a, *q = b;

#if 0
    for(i=0; i<5; i++){
        for(j=0; j<5; j++){
            if(a[i]<b[k]){
                printf("%d ",a[i]);
                break;
            }else{
                printf("%d ",b[k++]);
            }
        }
        if(i == 4 && 4 == k){
            printf("%d",b[k]);
        }
    }
#else
    for(i=0; i<5; i++){
        for(j=0; j<5; j++){
            if(*(a+i) < *(b+k)){
                printf("%d ",*(a+i));
                break;
            }else{
                printf("%d ",*(b + k++));
            }
        }
        if(i == 4 && 4 == k){
            printf("%d",*(b+k));
        }
    }
#endif

    printf("\n");
    return 0;
}
==================================
#include <stdio.h>

int main(void)
{
	int a[5] = {1, 3, 5, 7, 9};
	int b[5] = {2, 4, 60, 80, 100};

	int *p = a; // int *p = &a[0];
	int *q = b;

	int i=0, j=0;

	while(1){

		if(i>=5 || j>=5)
			break;

		if(*p < *q){
			printf("%d\n", *p);
			i++;
			p = a + i;
		}
		else{
			printf("%d\n", *q);
			j++;
			q = b + j;
		}
	}

	if(i < 5)
		while(i++ < 5){
			printf("%d\n", *p);
			p = a + i;
		}
	else
		while(j++ < 5){
			printf("%d\n", *q);
			q = b + j;
		}

	return 0;
}
  1. 定义字符指针数组char *str[5]分别指向5个字符串常量,从小到大输出字符串的内容。

#include <stdio.h>
#include <string.h>

int main(void)
{
    int i;
    char ch[5];
    char* str[5] = {"bwer","asdf","rxcv","dyui","zhjk"};
#if 1
    for(int j = 0; j < 4; j++){
        for(i = 0; i < 4-j; i++){
            if(strcmp(*(str+i+1),*(str+i)) < 0 ){
                strcpy(ch,*(str+i));
                *(str+i) = *(str+i+1);
                *(str+i+1) = ch;
            }
        }
    }

    for(i = 0; i < 5; i++){
        printf("%s ",*(str+i));
    }
    printf("\n");
#else
    i=1;
    printf("%s %s\n",*(str+i),*(str+i+1));
    strcpy(ch,*(str+i));
    *(str+i) = *(str+i+1);
    *(str+i+1) = ch;
    printf("%s %s\n",*(str+i),*(str+i+1));
#endif
    return 0;
}
===================================
#include <stdio.h>
#include <string.h>

int main(void)
{
	char *str[5] = { "this",
			 "is",
			 "a",
			 "testing",
			 "string"};

	int i = 0, j = 0;
	char *p;

	while(i < 5){
		j = 0;
		while(j < 4){
			if(strcmp(str[j], str[j+1]) < 0){
				j++;
				continue;
			}
			else{
				p = str[j];
				str[j] = str[j+1];
				str[j+1] = p;
			}
			j++;
		}
		i++;
	}

	for(i=0; i<5; i++)
		printf("%s\n", str[i]);
	
	return 0;
}
  1. 已知数组内容如下s[]={1,2,3,4,5,6,7,8,9}, 输入一个数n(1 <= n <= 9),使得该数组内容顺序后移n个位置。如n=3时,数组后移3个位置后的内容为{7,8,9,1,2,3,4,5,6}

#include <stdio.h>

int main(void)
{
    int a[] = {1,2,3,4,5,6,7,8,9};
    int b;
    int *p = a;

    printf("请输入一个数:");
    scanf("%d",&b);

#if 0
    for(int i = 0; i < b; i++){
        printf("%d ",a[9-b+i]);
    }
    for(int i = 0; i < 9-b; i++){
        printf("%d ",a[i]);
    }
    printf("\n");
#else
    for(int i = 0; i < b; i++){
        printf("%d ",*(p+9-b+i));
    }
    for(int i = 0; i < 9-b; i++){
        printf("%d ",*(p+i));
    }
    printf("\n");

#endif
    return 0;
}
  1. 输入一个字符串,内有数字和非数字字符,如 a123x456 17960? 302tab5876 将其中连续的数字作为一个整数,依次存放到整型数组a中。例如,123放在a[0],456放在a[1],统计共有多少个整数,并输出这些数。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZE1 64
#define SIZE2 20

int main(void)
{
	/***************************
	   buf should be set to 0
	****************************/
	char buf[SIZE1] = {[0 ... SIZE1-1] = '\0'};
	fgets(buf, SIZE1, stdin);

	int array[SIZE2] = {[0 ... SIZE2-1] = 0};
	char tmp[SIZE2];
	int begin=0, end=0, i=0;

	while(begin < SIZE1){

		memset(tmp, 0, SIZE2);

		/************************************
		   locate the beginning of a digit
		*************************************/
		while(buf[begin]<'0' || buf[begin]>'9')
			begin++;

		end = begin + 1;

		/*********************************
		   locate the end of the digit
		**********************************/
		while(buf[end]>='0' && buf[end]<='9')
			end++;

		strncpy(tmp, buf+begin, end-begin);
		array[i++] = atoi(tmp);

		/*********************************
		   search the next digit, start
		   the next character at "end+1"
		**********************************/
		begin = end + 1;
	}

	printf("digit number: %d\n", --i);
	printf("they are: ");
	int j = 0;
	while(j < i)
		printf("%d\t", array[j++]);
	printf("\n");

	return 0;
}

函数

  1. 编写函数分别实现以下功能:(1)求两个数之和;(2)求两个数之差;(3)求两个数之积。

#include <stdio.h>
//定义元素类型
typedef int elem_t;
//相加  通过返回值调用
elem_t add(elem_t a, elem_t b){
    return a + b;
}
//相减  通过指针调用
void sub(elem_t a, elem_t b, elem_t *p){
    *p = a - b;
}
//相乘  通过指针函数调用
elem_t *multiply(elem_t a, elem_t b){
    static elem_t p;
    p = a * b;
    return &p;
}

int main(void)
{
    elem_t a = 7, b = 5, c;

    sub(a,b,&c);
    printf("%d\n",add(a,b));
    printf("%d\n",c);
    printf("%d\n",*(multiply(a,b)));
    return 0;
}
  1. 编写一个函数,包括一个字符参数和两个整型参数。字符参数是需要输出的字符,第一个整型参数说明了在每行中该字符输出的个数,而第二个整型参数指的是需要输出的行数,编写一个调用该函数的程序。

#include <stdio.h>

void printf_str(char str[][4], int i, int j)
{
    for(int n = 0; n < i; n++){
        for(int m = 0; m < j; m++){
            printf("%c ",str[n][m]);
        }
    }

    printf("\n");
}

int main(void)
{
    char str[][4] = {"qiu","xia","zhe","nha","oka"};
	//传递数组名 和 字符串大小
    printf_str(str,5,4);

    return 0;
}
===================================
#include <stdio.h>

void draw_square(char x, int column, int row)
{
	int i=0, j;

	while(i++ < row){

		j = 0;
		while(j++ < column)
			printf("%c", x);

		printf("\n");
	}
}

int main(void)
{
	int column, row;

	printf("column and row: ");
	scanf("%d%d", &column, &row);

	draw_square('*', column, row);

	return 0;
}
  1. 编写一个函数taxis()实现数组的排序,在函数中调用swap()实现两个数的交换。打印出排序结果。

#include <stdio.h>
//数组的排序
void taix(int str[], int i)
{
    for(int n = i; n > 0; n--){
        //使最大值排到最后边
        for(int m = 0; m < n; m++){
            if(str[i] > str[i+1]){
                int tmp = str[i];
                str[i] = str[i+1];
                str[i] = str[i+1];
            }
        }
    }
	//打印数组
    for(int j = 0; j < i; j++){
        printf("%d ",str[j]);
    }

    printf("\n");
}

int main(void)
{
    char str[] = {2,4,7,2,3,8,4,8,9,2};
	//计算数组长度
    int len = sizeof(str) / sizeof(str[0]);

    taix(str,len);

    return 0;
}
  1. 编写一个函数,实现两个字符串的比较。

#include <stdio.h>
#include <string.h>

void trcmp(char *str1, char *str2){
    for(int i = 0; i < strlen(str1); i++){
        if(str1[i] == str2[i]){
            continue;
        }else if(str1[i] > str2[i]){
            printf("%s",str1);
        }else{
            printf("%s",str2);
        }
        break;
    }
    printf("\n");
}

int main(void)
{
    char str1[] = "qwer";
    char str2[] = "asdf";

    trcmp(str1,str2);

    return 0;
}
  1. 编写一个函数is-within().它接受两个参数,一个是字符,另一个是字符串指针。其功能是如果字符在字符串中。就返回1(真);如果字符不在字符串中,就返回0(假)。在一个使用循环语句为这个函数提供输入的完整程序中进行测试。

#include <stdio.h>
#include <string.h>

_Bool is_within(char ch, char *q)
{
    for(int i = 0; i < strlen(q); i++){
        if(ch == q[i]){
            return 1;
        }
    }
    return 0;
}

int main(void)
{
    char ch[] = "qwer";

    for(int i = 0; i < strlen(ch); i++){
        int ret = is_within(ch[i],ch);
        printf("%d ",ret);
    }

    printf("\n");

    return 0;
}
  1. 输出程序运行时的命令行参数。例如:

#include <stdio.h>

int main(int argc, char *argv[])
{
	int i=0;
	while(i++ < argc-1)
		printf("%s\t", argv[i]);
	printf("\n");

	return 0;
}

./myprog a b c

a b c

  1. 以下函数拍的功能是用递归的方法计算x的n阶勒让德多项式的值。已有调用语句p(n,x);编写函数实现功能。递归公式如下:

#include <stdio.h>

float legendre(int n, int x)
{
	if(n == 0)
		return 1;
	if(n == 1)
		return x;

	int m = (2*n-1)*x*legendre(n-1, x) - (n-1)*legendre(n-2, x);

	return m/n;
}

int main(void)
{
	printf("input n, x:\n");
	int n, x;

	scanf("%d%d", &n, &x);

	printf("%f\n", legendre(n, x));

	return 0;
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值