前言
最近在复习数据结构,突然想起了之前用C和C++写的数据结构代码,现在将其发布到CSDN,方便日后查看。
更详细的代码和其他常用数据结构的实现在GitHub上,欢迎大家关注
https://github.com/VandarkhoIme/Algorithm
DataElement.h
定义了数据元素
#ifndef DATAELEMENT_H_INCLUDED
#define DATAELEMENT_H_INCLUDED
#define MAX_SIZE 255
//¶¨ÒåÊý¾ÝÔªËØ
typedef struct{
int id;
char name[255];
}ElementType;
#endif // DATAELEMENT_H_INCLUDED
BinaryLinkedList.h
//二叉链表(二叉树的链式存储结构)
#ifndef BINARYLINKEDLIST_H_INCLUDED
#define BINARYLINKEDLIST_H_INCLUDED
#include "DataElement.h"
//定义二叉链表结点的存储结构
typedef struct BiNode{
int key; //按照完全二叉树的方法给树的结点编号
int status; //判断该结点是否成功创建
ElementType data; //数据域
struct BiNode * lchild; //左孩子(指针域)
struct BiNode * rchild; //右孩子(指针域)
}BiNode;
//以b为根节点,创建二叉树
void CreateBinaryLinkedList(BiNode * b);
//以下3个函数是CreateBinaryLinkedList的子函数,用来配合它使用的
void PreCreate(BiNode * b); //前序创建
void InCreate(BiNode * b); //中序创建
void PostCreate(BiNode * b); //后序创建
//以某种顺序遍历二叉树
void TraverseBinaryTree(BiNode *b);
//以下6个函数是TraverseBinaryTree的子函数.
void PreOrderTraverse(BiNode *b); //前序遍历
void InOrderTraverse(BiNode *b); //中序遍历
void PostOrderTraverse(BiNode *b); //后序遍历
void InOrderTraverse_Re(BiNode *b); //中序遍历的非递归算法
void PreOrderTraverse_Re(BiNode *b); //前序遍历的非递归算法
void PostOrderTraverse_Re(BiNode *b); //后序遍历的非递归算法 注意 这里有坑。后序遍历的非递归算法比较复杂。暂不实现
#endif // BINARYLINKEDLIST_H_INCLUDED
BinaryLinkedList.c
相当于Java的interface
#include "BinaryLinkedList.h"
#include "LinkedStack.h"
#include <stdio.h>
#include <stdlib.h>
void CreateBinaryLinkedList(BiNode * b){
printf("请选择创建方式(前序创建输入1,中序创建输入2,后序创建输入3):\n");
int a;
scanf("%d", &a);
//开始创建二叉树
if(a == 1){
printf("开始前序创建二叉树\n");
PreCreate(b);
}
else if(a == 2){
printf("开始中序创建二叉树\n");
InCreate(b);
}
else if(a == 3){
printf("开始后序创建二叉树\n");
PostCreate(b);
}
else{
printf("输入的创建方式有误,无法创建");
return;
}
printf("创建完成\n");
}
//三种创建二叉树(前序中序后序)的函数实现
void PreCreate(BiNode * b){
ElementType e;
printf("请输入结点的id(如果输入-1,那么就不在这个枝干上创建结点):\n");
scanf("%d",&e.id);
if(e.id == -1){ //如果用户输入了-1,那么将该结点的状态设为-999999,等函数返回之后释放该节点
b->status = -999999;
return;
}
printf("请输入结点的name:\n");
scanf("%s",e.name);
//以下
b->data = e; //将输入的结点信息赋值给当前结点的数据域
b->lchild = (BiNode *)malloc(sizeof(BiNode)); //给左孩子指针分配内存
PreCreate(b->lchild); //递归创建左子树
if(b->lchild->status == -999999){ //如果创建失败,那么删除刚刚分配的左孩子的内存,并且将指针置空
free(b->lchild);
b->lchild = NULL;
}
b->rchild = (BiNode *)malloc(sizeof(BiNode)); //给右孩子指针分配内存
PreCreate(b->rchild); //递归创建右子树
if(b->rchild->status == -999999){ //如果创建失败,那么删除刚刚分配的右孩子的内存,并且将指针置空
free(b->rchild);
b->rchild = NULL;
}
}
void InCreate(BiNode * b){
}
void PostCreate(BiNode * b){
}
//以下是遍历算法
void TraverseBinaryTree(BiNode *b){
printf("请选择遍历方式(前序遍历输入1,中序遍历输入2,后序遍历输入3\n前序非递归遍历输入4,中序非递归遍历输入5,后序非递归遍历输入6):\n");
int a;
scanf("%d", &a);
//开始遍历二叉树
if(a == 1){
printf("开始前序遍历二叉树\n");
PreOrderTraverse(b);
}
else if(a == 2){
printf("开始中序遍历二叉树\n");
InOrderTraverse(b);
}
else if(a == 3){
printf("开始后序遍历二叉树\n");
PostOrderTraverse(b);
}
else if(a == 4){
printf("开始前序非递归遍历二叉树\n");
PreOrderTraverse_Re(b);
}
else if(a == 5){
printf("开始中序非递归遍历二叉树\n");
InOrderTraverse_Re(b);
}
else if(a == 6){
printf("开始后序非递归遍历二叉树\n");
PostOrderTraverse_Re(b);
}
else{
printf("输入的遍历方式有误,无法遍历");
return;
}
printf("遍历完成\n");
}
void PreOrderTraverse(BiNode *b){
if(b == NULL) //对应上面的一大串注释。这里就是通过if语句判断指针是否为NULL
return;
printf("%d\t%s\n",b->data.id,b->data.name);
PreOrderTraverse(b->lchild);
PreOrderTraverse(b->rchild);
}
void InOrderTraverse(BiNode *b){
if(b == NULL)
return;
InOrderTraverse(b->lchild);
printf("%d\t%s\n",b->data.id,b->data.name);
InOrderTraverse(b->rchild);
}
void PostOrderTraverse(BiNode *b){
if(b == NULL)
return;
PostOrderTraverse(b->lchild);
PostOrderTraverse(b->rchild);
printf("%d\t%s\n",b->data.id,b->data.name);
}
void InOrderTraverse_Re(BiNode *b){
//中序遍历的非递归算法
//王道考研数据结构 以中序遍历为例讲解算法思想。那么就先实现非递归的中序遍历。
//算法思想:
//1.初始时扫描根结点进栈,并扫描根结点的所有左侧结点并将它们一一进栈
//2.出栈一个结点,访问它(在这里是打印它)
//3.扫描该节点的右孩子结点将其进栈(只扫描它的右孩子!不是所有)
//4.依次扫描右孩子结点的左侧结点并将它们一一进栈(其实就是第1步的重复。将右孩子结点看作了根结点)
//5.反复该过程直到栈空为止。
LinkedStack *s = (LinkedStack*)malloc(sizeof(LinkedStack)); //创建一个链栈
InitLinkedStack(s);
BiNode * temp = b; //创建一个中间变量保存形参方便后续操作
while(temp != NULL || s->length != 0){ //只要结点存在或者栈非空,那么就继续循环
if(temp != NULL){
Push(s,*temp); //第一步:让根节点进栈
temp = temp->lchild; //通过循环让根节点的左孩子们进栈
}
else{ //else代表结点空了
BiNode * t = (BiNode*)malloc(sizeof(BiNode));
Pop(s,t); //注意 这里不是将空结点扔出去。空结点根本就没有进栈
// 这里是出栈一个真实的结点。
//出栈真实的那个结点,存在了临时变量t里面
printf("%d\t%s\n",t->data.id,t->data.name);
temp = t->rchild; //用一个临时变量t保存该结点,然后将temp赋值给t的右孩子
free(t); //用完空间之后记得释放,并且将指针置空。避免产生野指针
t = NULL;
}
}
free(s);
}
void PreOrderTraverse_Re(BiNode *b){ //前序遍历的非递归算法
//和中序遍历差不多。就是代码顺序有改变 我把注释都删了
LinkedStack *s = (LinkedStack*)malloc(sizeof(LinkedStack));
InitLinkedStack(s);
BiNode * temp = b;
while(temp != NULL || s->length != 0){
if(temp != NULL){
printf("%d\t%s\n",temp->data.id,temp->data.name); //和中序遍历不同顺序。这里是先打印
Push(s,*temp);
temp = temp->lchild;
}
else{
BiNode * t = (BiNode*)malloc(sizeof(BiNode));
Pop(s,t);
temp = t->rchild;
free(t);
t = NULL;
}
}
free(s);
}
void PostOrderTraverse_Re(BiNode *b){ //后序遍历的非递归算法 注意 这里有坑。后序遍历的非递归算法比较复杂。暂不实现
;
}
LinkedStack.h
#ifndef LINKEDSTACK_H_INCLUDED
#define LINKEDSTACK_H_INCLUDED
//链栈
//这个链栈用来非递归遍历二叉树而特别制造
#include <stdio.h>
#include <stdlib.h>
#include "BinaryLinkedList.h"
//结点 注意data就是二叉树的结点
typedef struct StackNode{
BiNode data;
struct StackNode * next;
}StackNode;
//存放栈顶指针的数据结构。里面有栈顶指针和栈的length
typedef struct LinkedStack{
StackNode * Top;
int length;
}LinkedStack;
//初始化栈
void InitLinkedStack(LinkedStack * s);
//压栈 将元素e压入栈中 返回值int为0代表失败,1为成功。
int Push(LinkedStack * s, BiNode e);
//删除栈S中的栈顶元素,并用e来返回弹出的值 返回值int为0代表失败,1为成功。
int Pop(LinkedStack * s, BiNode * e);
//判断栈是否为空
void IsStackEmpty(LinkedStack * s);
#endif // LINKEDSTACK_H_INCLUDED
LinkedStack.c
#include "LinkedStack.h"
#include <stdlib.h>
//初始化栈
void InitLinkedStack(LinkedStack * s){
s->Top = NULL;
s->length = 0;
}
int Push(LinkedStack * s, BiNode e){
StackNode * node = (StackNode *)malloc(sizeof(StackNode)); //创建一个结点,节点里存放新压入元素e的信息
node->data = e;
node->next = s->Top;
s->Top = node;
s->length++;
return 1;
}
int Pop(LinkedStack * s, BiNode* e){
*e = s->Top->data;
StackNode * node = s->Top;
s->Top = s->Top->next;
free(node);
node = NULL;
s->length--;
return 1;
}
void IsStackEmpty(LinkedStack * s){
}
main.c
主函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "DataElement.h"
#include "BinaryLinkedList.h"
void TestBinaryLinkedList();
int main()
{
TestBinaryLinkedList();
return 0;
}
void TestBinaryLinkedList(){
BiNode * node = (BiNode *)malloc(sizeof(BiNode));
CreateBinaryLinkedList(node);
TraverseBinaryTree(node);
free(node);
node = NULL;
}