内容概述
实例代码
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练习:
指针
编写一个程序实现功能:将字符串”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;
}
用指针将整型组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");
}
编写一个程序实现功能:将两个字符串合并为一个字符串并且输出,用指针实现。
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;
}
编写一个程序实现以下功能:用指针数组处理一个二维数组,求出二维数组所有元素的和。
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;
}
已知数组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;
}
定义字符指针数组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;
}
已知数组内容如下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;
}
输入一个字符串,内有数字和非数字字符,如 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)求两个数之和;(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;
}
编写一个函数,包括一个字符参数和两个整型参数。字符参数是需要输出的字符,第一个整型参数说明了在每行中该字符输出的个数,而第二个整型参数指的是需要输出的行数,编写一个调用该函数的程序。
#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;
}
编写一个函数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;
}
编写一个函数,实现两个字符串的比较。
#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;
}
编写一个函数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;
}
输出程序运行时的命令行参数。例如:
#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
以下函数拍的功能是用递归的方法计算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;
}