学习所有语言的第一步几乎都是在控制台输出"Hello World",C语言也是如此,C语言支持结构化编程、词汇范围和递归等特性,C语言编写的代码在稍作修改或无需修改的情况下可以在多种不同的操作系统和平台上编译和运行,同时运行速度极快。但C语言的缺点也较为明显:作为过程式编程语言,没有内置的面向对象编程(OOP)特性,如类、继承和多态,同时缺少一些高级特性,如泛型编程、异常处理等,指针操作和内存管理也很让人头疼。
使用链表+二叉树输出"Hello, World"
在C语言中链表、指针、二叉树都是很重要的概念,链表用于需要动态存储和频繁插入、删除操作的场景,而二叉树则适用于需要有序存储和快速查找、搜索的场景。
这里先定义包含包含字符数据data
和指向下一个节点的指针next的
链表节点Node,再定义一个二叉树节点TreeNode,让它包含字符数据data
,以及指向左子节点和右子节点的指针。随后定义用于表示函数执行状态的枚举OutputStatus
,让它包含包含SUCCESS
和FAILURE。
随后既是对链表和二叉树进行创建节点、添加节点、插入节点、释放节点等操作,这里为了代码的整洁美观,我特地使用了多级指针,在略缩图看上去还是很给力的:
#include <stdio.h>
#include <stdlib.h>
// 定义链表节点结构体
typedef struct Node {
char data;
struct Node* next;
} Node;
// 定义二叉树节点结构体
typedef struct TreeNode {
char data;
struct TreeNode* left;
struct TreeNode* right;
} TreeNode;
// 定义输出状态枚举
typedef enum {
SUCCESS,
FAILURE
} OutputStatus;
// 创建链表节点
Node* createNode(char data) {
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL) {
return NULL;
}
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// 创建二叉树节点
TreeNode* createTreeNode(char data) {
TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
if (newNode == NULL) {
return NULL;
}
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
// 添加节点到链表末尾
void appendNode(Node** head, char data) {
Node* newNode = createNode(data);
if (*head == NULL) {
*head = newNode;
} else {
Node* temp = *head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
}
// 插入节点到二叉树
void insertTreeNode(TreeNode** root, char data) {
if (*root == NULL) {
*root = createTreeNode(data);
return;
}
if (data < (*root)->data) {
insertTreeNode(&((*root)->left), data);
} else {
insertTreeNode(&((*root)->right), data);
}
}
// 释放二叉树内存
void freeAllTreeNodes(TreeNode* root) {
if (root == NULL) {
return;
} else {
freeAllTreeNodes(root->left);
freeAllTreeNodes(root->right);
free(root);
}
}
// 输出链表的内联函数
static inline OutputStatus printList(Node* head) {
Node* temp = head;
while (temp != NULL) {
printf("%c ", temp->data);
temp = temp->next;
}
printf("\n");
return SUCCESS;
}
// 前序遍历打印二叉树
void printTree(TreeNode* root) {
if (root != NULL) {
printf("%c ", root->data);
printTree(root->left);
printTree(root->right);
}
}
// 释放链表内存
void freeAllNodes(Node* head) {
if (head == NULL) {
return;
} else {
freeAllNodes(head->next);
free(head);
}
}
int main() {
Node* head = NULL;
TreeNode* root = NULL;
// 使用指针操作链表和二叉树
char H = 'H';
char W = 'W';
char O = 'o';
char L = 'l';
char D = 'd';
char E = 'e';
char R = 'r';
char S = ',';
char * g = &H;
char * a = &W;
char * y = &O;
char * b = &L;
char * o = &D;
char * q = &E;
char * s = &R;
char * ptr = &S;
char ** ptr1 = &ptr;
char *** ptr2 = &ptr1;
char **** ptr3 = &ptr2;
char ***** ptr4 = &ptr3;
char ****** ptr5 = &ptr4;
char ******* ptr6 = &ptr5;
char ******** ptr7 = &ptr6;
char ********* DouHao = &ptr7;
// 向链表添加数据
appendNode(&head, *g);
appendNode(&head, *q);
appendNode(&head, *b);
appendNode(&head, *b);
appendNode(&head, *y);
appendNode(&head, ********* DouHao);
// 向二叉树插入数据
insertTreeNode(&root, *a);
insertTreeNode(&root, *y);
insertTreeNode(&root, *s);
insertTreeNode(&root, *b);
insertTreeNode(&root, *o);
// 输出链表
printList(head) == SUCCESS;
// 输出二叉树
printTree(root);
printf("\n");
// 释放链表内存
freeAllNodes(head);
// 释放二叉树内存
freeAllTreeNodes(root);
return 0;
}
单独使用链表输出"Hello, World"
上述的实在过于复杂,我们需要对它进行简化,只使用链表来进行操作,这样可以大大的提升代码的可维护能力,同时降低了代码的复杂度
#include <stdio.h>
#include <stdlib.h>
struct Node {
char data;
struct Node* next;
};
struct Node* createNode(char data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (newNode == NULL) {
printf("Memory allocation failed\n");
exit(1);
}
newNode->data = data;
newNode->next = NULL;
return newNode;
}
void appendNode(struct Node** head, char data) {
struct Node* newNode = createNode(data);
if (*head == NULL) {
*head = newNode;
} else {
struct Node* temp = *head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
}
void printList(struct Node* head) {
struct Node* temp = head;
while (temp != NULL) {
printf("%c", temp->data);
temp = temp->next;
}
printf("\n");
}
int main() {
struct Node* head = NULL;
char* str = "Hello, World";
for (int i = 0; str[i] != '\0'; i++) {
appendNode(&head, str[i]);
}
printList(head);
return 0;
}
使用堆栈输出"Hello, World"
虽然单独使用链表大大降低了操作难度,但还是较为复杂,于是我思考可不可以换一种思维模式,使用堆栈来完成输出呢,于是我再次优化代码:
先定义一个Stack
结构体,包含一个字符数组items
用于存储堆栈中的元素,和一个整数top
用于指示堆栈顶部元素的位置。随后初始化堆栈,定义一个initStack
函数接受一个指向Stack
结构体的指针,并将top
成员初始化为-1
,表示堆栈为空。再定义函数isFull
检查堆栈是否已满,即top
成员是否等于MAX_SIZE - 1
。isEmpty
函数检查堆栈是否为空,即top
成员是否等于-1
。最后既可以使用push
函数接受一个指向Stack
结构体的指针和一个字符item
,如果堆栈未满,则将item
添加到堆栈顶部,并递增top
成员。最后可以将“dlroW olleH”转化为"Hello World"并输出出来
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100
// 定义个堆栈结构体
struct Stack {
char items[MAX_SIZE];
int top;
};
// 初始化堆栈并检查堆栈
void initStack(struct Stack* stack) {
stack->top = -1;
}
int isFull(struct Stack* stack) {
return stack->top == MAX_SIZE - 1;
}
int isEmpty(struct Stack* stack) {
return stack->top == -1;
}
// 向堆栈中添加元素
void push(struct Stack* stack, char item) {
if (isFull(stack)) {
printf("堆满了\n");
return;
}
stack->items[++stack->top] = item;
}
// 从堆栈中移除元素
char pop(struct Stack* stack) {
if (isEmpty(stack)) {
printf("堆空了\n");
return '\0';
}
return stack->items[stack->top--];
}
int main() {
struct Stack stack;
initStack(&stack);
char* str = "dlroW olleH";
for (int i = 0; str[i] != '\0'; i++) {
push(&stack, str[i]);
}
while (!isEmpty(&stack)) {
printf("%c", pop(&stack));
}
printf("\n");
return 0;
}
使用十六进制输出"Hello, World"
使用堆栈的操作是的代码量只有第一版的30%,操作也变得简单,但是每次打字都是倒着输入比较不爽,所以为了用户的体验感,我选择再一次优化代码 ,我选择的是使用十六进制ASCII码,操作一下就变得简单起来了呢。
#include <stdio.h>
int main() {
unsigned char charData[] = {0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64};
for (int i = 0; i < sizeof(charData); i++) {
printf("%c", charData[i]);
}
printf("\n");
return 0;
}
使用<unistd.h>头文件输出"Hello, World"
虽然十六进制ASCII码已经很好了,但是还需要再次优化,因为不可能总是去查ASCII表,于是我尝试了使用<unistd.h>头文件,这次的代码变得更简洁了
#include <unistd.h>
int main() {
write(1, "hello world\n", 12);
return 0;
}
使用<stdio.h>头文件输出"Hello, World"
<unistd.h>头文件存在一个问题,就是在很多平台可能无法使用,于是我在苦苦思索如何更加简洁的输出"Hello World"时,发现<stdio.h>非常适合,尝试了一下后代码运行正常:
#include<stdio.h>
int main()
{
printf("Hello World");
return 0;
}
最后在我的 大力优化下,代码量从最初的160行降低到6行,运行速度也大大滴提升了!