C语言数据结构
实验
实验二
#include<iostream>
#include"string"
#include<queue>
using namespace std;
template<typename E>
class BinNode//结点类
{
private:
BinNode* lc;//左孩子
BinNode* rc;//右孩子
E elem;
public:
BinNode()//默认构造函数,设置左右孩子为空
{
lc = rc = NULL;
}
BinNode(E tmp, BinNode* l = NULL, BinNode* r = NULL)//带参构造函数
{
elem = tmp;
lc = l;
rc = r;
}
BinNode* left()//返回左孩子
{
return lc;
}
BinNode* right()//返回右孩子
{
return rc;
}
void setLeft(BinNode* l)//设置左孩子
{
lc = l;
}
void setRight(BinNode* r)//设置右孩子
{
rc = r;
}
void setValue(E tmp)//设置当前结点的值
{
elem = tmp;
}
E getValue()//获得当前结点的值
{
return elem;
}
bool isLeaf()//判断当前结点是否为叶子结点
{
return (lc == NULL) && (rc == NULL);
}
};
template<typename E>
class BinTree//二叉树类
{
private:
BinNode<E>* root;//根结点
void clear(BinNode<E>* r)//清空二叉树
{
if (r == NULL) return;
clear(r->left());
clear(r->right());
delete r;
}
void preOrder(BinNode<E>* tmp, void(*visit)(BinNode<E>* node))//先序遍历,void(*visit)(BinNode<E>*node)为一个函数指针参数,用visit代替传进来的函数,在遍历函数中使用传进来的函数功能
{
if (tmp != NULL) {
visit(tmp);
preOrder(tmp->left(), visit);
preOrder(tmp->right(), visit);
}
}
void inOrder(BinNode<E>* tmp, void(*visit)(BinNode<E>* node))//中序遍历,void(*visit)(BinNode<E>*node)为一个函数指针参数,用visit代替传进来的函数,在遍历函数中使用传进来的函数功能
{
if (tmp != NULL) {
inOrder(tmp->left(), visit);
visit(tmp);
inOrder(tmp->right(), visit);
}
}
void postOrder(BinNode<E>* tmp, void(*visit)(BinNode<E>* node))//后序遍历,void(*visit)(BinNode<E>*node)为一个函数指针参数,用visit代替传进来的函数,在遍历函数中使用传进来的函数功能
{
if (tmp != NULL) {
postOrder(tmp->left(), visit);
postOrder(tmp->right(), visit);
visit(tmp);
}
}
void LevelOrderTranverse(BinNode<E>* tmp, void(*visit)(BinNode<E>* node))//层次遍历,void(*visit)(BinNode<E>*node)为一个函数指针参数,用visit代替传进来的函数,在遍历函数中使用传进来的函数功能
{
queue<BinNode<E>*> q;
if (tmp != NULL) { q.push(tmp); }//压入队尾
BinNode<E>* b;
while (!q.empty()) {
b = q.front();//b等于队头元素
visit(b);
q.pop();//弹出队头元素
if (b->left()) {
q.push(b->left());//压入b的左孩子
}
if (b->right()) {
q.push(b->right());//压入b的右孩子
}
}
}
int BinTreeDepth(BinNode<E>* tmp)//获得二叉树的深度
{
if (BinTreeHeight(tmp) > 0) return BinTreeHeight(tmp) - 1;
else return 0;
}
int BinTreeNodes(BinNode<E>* tmp)//获得二叉树的结点数
{
if (tmp != NULL)
{
return (BinTreeNodes(tmp->left()) + BinTreeNodes(tmp->right()) + 1);
}
else return 0;
}
int BinTreeHeight(BinNode<E>* tmp)//获得二叉树的高度
{
if (tmp == NULL)
{
return 0;
}
if (tmp->isLeaf())
{
return 1;
}
int lh = BinTreeHeight(tmp->left());
int rh = BinTreeHeight(tmp->right());
return 1 + (lh > rh ? lh : rh);
}
int BinTreeLeafs(BinNode<E>* tmp)//获得二叉树的叶子结点数
{
if (tmp == NULL) return 0;
if (tmp->isLeaf()) return 1;
return BinTreeLeafs(tmp->left()) + BinTreeLeafs(tmp->right());
}
bool find(BinNode<E>* tmp, E e)//查找二叉树中是否含有某个名为e的结点
{
if (tmp == NULL) return false;
if (tmp->getValue() == e) return true;
bool lresult = find(tmp->left(), e);
bool rresult = find(tmp->right(), e);
return lresult || rresult;
}
public:
BinTree()//默认构造函数
{
root = new BinNode<E>;
}
~BinTree()//析构函数
{
clear(root);
}
bool BinTreeEmpty()//判断二叉树是否为空
{
if (root == NULL)
return true;
else
return false;
}
BinNode<E>* getRoot()//获得根节点
{
return root;
}
void setRoot(BinNode<E>* r)//设置根节点
{
root = r;
}
//下面的函数是对外的函数,所以内部还会有一些同名的函数,但是参数列表不一样,实现数据的封装,外部的调用不会涉及到内部的数据对象
void clear()//清空二叉树
{
clear(root);
root = NULL;
}
void preOrder(void(*visit)(BinNode<E>* node))//先序遍历,传入相对应的访问函数即可对该当前结点实现不同功能的访问(本程序为输出)
{
preOrder(root, visit);
}
void inOrder(void(*visit)(BinNode<E>* node)) //先序遍历,传入相对应的访问函数即可对该当前结点实现不同功能的访问(本程序为输出)
{
inOrder(root, visit);
}
void postOrder(void(*visit)(BinNode<E>* node))//先序遍历,传入相对应的访问函数即可对该当前结点实现不同功能的访问(本程序为输出)
{
postOrder(root, visit);
}
void LevelOrderTranverse(void(*visit)(BinNode<E>* node))//先序遍历,传入相对应的访问函数即可对该当前结点实现不同功能的访问(本程序为输出)
{
LevelOrderTranverse(root, visit);
}
int BinTreeDepth()//获得二叉树深度
{
return BinTreeDepth(root);
}
int BinTreeNodes()//获得二叉树结点数
{
return BinTreeNodes(root);
}
int BinTreeHeight()//获得二叉树高度
{
return BinTreeHeight(root);
}
int BinTreeLeafs()//获得二叉树叶子结点数
{
return BinTreeLeafs(root);
}
bool find(E e)//查找二叉树中是否存在名为e的结点
{
return find(root, e);
}
};
template<typename E>
void printNode(BinNode<E>* tmp)//打印结点的值的函数
{
cout << tmp->getValue() << " ";
}
template<typename E>
BinNode<E>* creatBinaryTree(string s[], int& x, int n)//构建二叉树的主函数,根据先序遍历,采用递归思想构建
{
if (s[x] == "/")
return NULL;
else
{
BinNode<E>* node = new BinNode<E>(s[x]);
x = x + 1;
if (x < n);
node->setLeft(creatBinaryTree<E>(s, x, n));
x = x + 1;
if (x < n);
node->setRight(creatBinaryTree<E>(s, x, n));
return node;
}
}
void creatBinaryTree(BinTree<string>* BT)//构建二叉树的函数,包含了上面的构建二叉树的主函数,仅仅起到了在主函数中简洁一些的作用
{
//cout << "现在进入构建二叉树程序......" << endl;
//cout << "请输入二叉树有多少个结点(空结点也计算其中)" << endl;
int n = 0;
cin >> n;
//cout << "请按preorder顺序输入,遇到NULL请输入'/',用空格隔开或者回车隔开均可以" << endl;
string* s = new string[n];
for (int i = 0; i < n; i++)
{
cin >> s[i];
}
int now = 0;
BT->setRoot(creatBinaryTree<string>(s, now, n));
}
int main()
{
//本程序的二叉树是一个模板类,若想改变为别的类型,可以在相关的地方在“<>”中修改相关参数,本程序默认为最具有普遍性的string
BinTree<string>* BT = new BinTree<string>;
creatBinaryTree(BT);
string strfind;
cin >> strfind;
//在这里,已经构建好了一棵二叉树
//下面是二叉树的基本函数操作的展示
cout << "0:判断是否为空树:";
if (BT->BinTreeEmpty() == true)
cout << "是" << endl;
else
cout << "否" << endl;
cout << "1:前序遍历:";
BT->preOrder(printNode);
cout << endl;
cout << "2:中序遍历:";
BT->inOrder(printNode);
cout << endl;
cout << "3:后序遍历:";
BT->postOrder(printNode);
cout << endl;
cout << "4:层次遍历:";
BT->LevelOrderTranverse(printNode);
cout << endl;
cout << "5:记录树的深度:";
cout << BT->BinTreeDepth() << endl;
cout << "6:记录树的高度:";
cout << BT->BinTreeHeight() << endl;
cout << "7:统计结点:";
cout << BT->BinTreeNodes() << endl;
cout << "8:统计叶子结点:";
cout << BT->BinTreeLeafs() << endl;
cout << "9:查找" << strfind << ":";
if (BT->find(strfind) == true)
cout << "存在" << endl;
else
cout << "不存在" << endl;
cout << "10:是否清空:";
BT->clear();
cout << "已清空" << endl;
cout << "5:记录树的深度:";
cout << BT->BinTreeDepth() << endl;
cout << "6:记录树的高度:";
cout << BT->BinTreeHeight() << endl;
cout << "7:统计结点:";
cout << BT->BinTreeNodes() << endl;
cout << "8:统计叶子结点:";
cout << BT->BinTreeLeafs() << endl;
return 0;
}
前言
结构体的使用
malloc()动态分配内存
#include <stdio.h>
#include <malloc.h>
int main ()
{
int a[5]={4,10,2,8,6};
int len;
scanf("%d",&len);
int *pArr = (int *)malloc(sizeof(int)*len);
for(int i=0; i<len; i++) scanf("%d",&pArr[i]);
for(int i=0; i<len; i++) printf("%d\n",*(pArr+i));
//*pArr = 4;//类似于a[0]=4;
//pArr[1] = 10;//类似于a[1]=10;
free(pArr);//把pArr所代表的动态分配的20个字节的内存释放
return 0;
}
连续存储数组的算法演示
#include<bits/stdc++.h>
using namespace std;
struct Arr
{
int* pBase;//存储的是数组第一个元素的地址
int len;//数组所能容纳的最大元素的个数
int cnt;//当前数组有效元素的个数
};
void init_arr(struct Arr *pArr,int length);//初始化
bool append_arr(struct Arr *pArr, int val);//尾加
bool insert_arr(struct Arr *pArr, int pos, int val); //插入值 pos的值从1开始
bool delete_arr(struct Arr *pArr, int pos, int* pVal);
bool is_empty(struct Arr* pArr);
bool is_full(struct Arr* pArr);
void sort_arr(struct Arr* pArr);
void show_arr(struct Arr* pArr);//打印数组
void inversion_arr(struct Arr* pArr);//倒置数组
int main()
{
struct Arr arr;
int val;
init_arr(&arr,6);
append_arr(&arr,1);
show_arr(&arr);
delete_arr(&arr,1,&val);
append_arr(&arr,2);
append_arr(&arr,3);
append_arr(&arr,4);
append_arr(&arr,5);
insert_arr(&arr,7,99);
show_arr(&arr);
inversion_arr(&arr);
show_arr(&arr);
sort_arr(&arr);
show_arr(&arr);
return 0;
}
void init_arr(struct Arr *pArr,int length)
{
pArr->pBase = (int*)malloc(sizeof(int)*length);
if(NULL == pArr->pBase)//如果分配不成功
{
cout<<"动态内存分配失败"<<endl;
exit(-1);//终止整个程序
}
else
{
pArr->len = length;
pArr->cnt = 0;
}
return;
}
bool append_arr(struct Arr *pArr, int val)
{
if(is_full(pArr)) return 0;//如果已满则加不进去 返回false
else//未满则增加val到末尾
{
pArr->pBase[(pArr->cnt)++] = val;
return 1;
}
}
bool insert_arr(struct Arr *pArr, int pos, int val)
{
if(is_full(pArr)) return 0;
if(pos<1 || pos>pArr->cnt+1) return 0;
for(int i=pArr->cnt-1; i>=pos-1; --i) pArr->pBase[i+1] = pArr->pBase[i];
pArr->pBase[pos-1] = val;
(pArr->cnt)++;
return 1;
}
bool delete_arr(struct Arr *pArr, int pos, int* pVal)
{
if(is_empty(pArr)) return 0;
if(pos<1 || pos>pArr->cnt) return 0;
*pVal=pArr->pBase[pos-1];//把要删除的值赋给*pVal
for(int i=pos; i<pArr->cnt;++i) pArr->pBase[i-1] = pArr->pBase[i];
pArr->cnt--;//有效个数减1
return 1;
}
bool is_empty(struct Arr* pArr)
{
if(0 == pArr->cnt) return 1;
else return 0;
}
bool is_full(struct Arr* pArr)
{
if(pArr->cnt == pArr->len) return 1;
else return 0;
}
void sort_arr(struct Arr* pArr)
{
for(int i=0;i<pArr->cnt-1;i++)//冒泡排序
{
for(int j=i+1;j<pArr->cnt;j++)
{
if(pArr->pBase[i]>pArr->pBase[j])
{
int temp = pArr->pBase[i];
pArr->pBase[i] = pArr->pBase[j];
pArr->pBase[j] = temp;
}
}
}
}
void show_arr(struct Arr* pArr)
{
if(is_empty(pArr)) cout<<"数组为空!"<<endl;
else
{
for(int i=0;i<pArr->cnt;i++) printf("%d ",pArr->pBase[i]);//先等于 再自增
cout<<endl;
}
}
void inversion_arr(struct Arr* pArr)
{
int i=0;
int j=pArr->cnt-1;
while(i<j)//互换
{
int temp = pArr->pBase[i];
pArr->pBase[i] = pArr->pBase[j];
pArr->pBase[j] = temp;
i++; j--;
}
return;
}
链表
typedef的用法
#include <stdio.h>
typedef int INT;//为int再取一个名字INT
typedef struct student
{
int sid;
char name[100];
char sex;
}* PST,ST;//ST为struct student, PST为struct student*
int main()
{
struct student st; //等价于ST st;
struct student* ps = &st;//等价于ST* ps = &st; 等价于PST ps = &st;
}
链表的定义
n个节点离散分配 彼此通过指针相连 首节点没有前驱节点 尾节点没有后续节点
5个专业术语
首节点:第一个有效节点
尾节点:最后一个有效节点
头节点:第一个有效节点之前的那个节点 头节点并不存放有效数据 加头结点的目的主要是为了方便堆链表操作 头节点数据类型和首节点一样
头指针:指向头结点的指针变量(存放头节点地址)
尾指针:指向尾结点的指针变量(存放尾节点地址)
**确定一个链表需要几个参数:**只需要一个参数:头指针
链表分类: 单链表
双链表:每个节点有两个指针域
循环链表:能通过任何一个节点找到其他所有节点
非循环链表
链表的实现
#include<bits/stdc++.h>
using namespace std;
typedef struct Node
{
int data;//数据域
struct Node* pNext;//指针域
}NODE,*PNODE;//NODE等价于struct Node PNODE等价于struct Node*
PNODE create_list();
void traverse_list(PNODE pHead);//遍历输出
void is_empty(PNODE pHead);
int length_list(PNODE);//求链表长度
bool insert_list(PNODE pHead,int pos,int val);//插入
bool delete_list(PNODE pHead ,int pos,int* val);//删除
void sort_list(PNODE);//排序
int main()
{
PNODE pHead = NULL;//等价于struct Node* pHead = NULL;
pHead = create_list(); //create_list()功能为创建一个非循环单链表,并将改链表头结点的地址赋给pHead
traverse_list(pHead);
is_empty(pHead);
cout<<"链表长度为:"<<length_list(pHead)<<endl;
void sort_list(PNODE pHead);
insert_list(pHead,3,33);
sort_list(pHead);
traverse_list(pHead);
return 0;
}
PNODE create_list()
{
int len;//用来存放有效节点的个数
int val;//用来存放用户输入的结点的值
//分配了一个不存放有效数据的头节点
PNODE pHead = (PNODE)malloc(sizeof(NODE));
if(NULL==pHead)
{
cout<<"分配失败,程序终止!"<<endl;
exit(-1);
}
//初始化pTail 永远指向最后一个节点
PNODE pTail = pHead;
pTail->pNext = NULL;
cout<<"请输入您需要生成的链表节点的个数:len=";
cin>>len;
for(int i=0;i<len;i++)
{
cout<<"请输入第"<<i+1<<"个节点的值:";
cin>>val;
PNODE pNew = (PNODE)malloc(sizeof(NODE));
if(NULL==pNew)
{
cout<<"分配失败,程序终止!"<<endl;
exit(-1);
}
pNew->data = val;//数据域赋值
//指针域赋值
pTail->pNext = pNew;
pNew->pNext = NULL;
pTail = pNew;
}
return pHead;
}
void traverse_list(PNODE pHead)
{
PNODE p = pHead->pNext;
while(NULL != p)
{
cout<<p->data<<" ";
p = p->pNext;
}
cout<<endl;
return;
}
void is_empty(PNODE pHead)
{
if(pHead->pNext == NULL)
{
cout<<"链表为空!"<<endl;
}
else
{
cout<<"链表不为空!"<<endl;
}
return;
}
int length_list(PNODE pHead)
{
PNODE p = pHead->pNext;
int len = 0;
while(NULL != p)
{
++len;
p = p->pNext;
}
return len;
}
//非常难 要多看
bool insert_list(PNODE pHead,int pos,int val)
{
int i=0;
PNODE p = pHead;
while(NULL!=p && i<pos-1)
{
p = p->pNext;
++i;
}
if(i>pos-1 || NULL==p) return 0;
PNODE pNew = (PNODE)malloc(sizeof(NODE));
if(NULL==pNew)
{
cout<<"动态内存分配失败!"<<endl;
exit(-1);
}
pNew->data = val;
PNODE q = p->pNext;
p->pNext = pNew;
pNew->pNext = q;
return 1;
}
//非常难 要多看
bool delete_list(PNODE pHead ,int pos,int* val)
{
int i=0;
PNODE p = pHead;
while(NULL!=p->pNext && i<pos-1)
{
p = p->pNext;
++i;
}
if(i>pos-1 || NULL==p->pNext) return 0;
PNODE q = p->pNext;
*val = q->data;
//删除p节点后面的节点
p->pNext = p->pNext->pNext;
free(q);
q = NULL;
return 1;
}
void sort_list(PNODE pHead)
{
PNODE p,q;
for(p=pHead->pNext;p->pNext!=NULL;p=p->pNext)
{
for(q=p->pNext;q!=NULL;q=q->pNext)
{
if(p->data > q->data)
{
int t=p->data;
p->data=q->data;
q->data=t;
}
}
}
return;
}
栈
简要介绍
定义:一种可以实现”先进后出“的存储结构
分类:静态栈 动态栈
栈的实现
#include<bits/stdc++.h>
using namespace std;
typedef struct Node
{
int data;//数据域
struct Node* pNext;//指针域
}NODE,*PNODE;//NODE等价于struct Node PNODE等价于struct Node*
typedef struct Stack
{
PNODE pTop;//不停变化
PNODE pBottom;//一般不变
}STACK,*PSTACK;
void init(PSTACK);//栈初始化
void push(PSTACK,int);//入栈
void traverse(PSTACK);//遍历输出
void pop(PSTACK,int*);//出栈
void clear(PSTACK pS);//清空
int main()
{
int val;//保存出战元素的值
STACK S;//STACK等价于struct Stack
init(&S);
push(&S,1);
push(&S,2);
push(&S,3);
push(&S,4);
push(&S,5);
push(&S,6);
traverse(&S);
pop(&S,&val);
traverse(&S);
clear(&S);
traverse(&S);
return 0;
}
void init(PSTACK pS)
{
pS->pTop = (PNODE)malloc(sizeof(NODE));
if(NULL==pS->pTop)
{
cout<<"动态内存分配失败!"<<endl;
exit(-1);
}
else
{
pS->pBottom = pS->pTop;
pS->pTop->pNext = NULL;//头节点指针域置为空
}
}
void push(PSTACK pS,int val)
{
PNODE pNew = (PNODE)malloc(sizeof(NODE));
pNew->data = val;
pNew->pNext = pS->pTop;//不能改成pS->pBottom
pS->pTop = pNew;
return;
}
void traverse(PSTACK pS)
{
PNODE p = pS->pTop;
while(p!=pS->pBottom)
{
cout<<p->data<<" ";
p = p->pNext;
}
cout<<endl;
return;
}
bool empty(PSTACK pS)
{
if(pS->pBottom == pS->pTop) return 1;
else return 0;
}
//把pS所指向的栈出栈一次 并把出栈元素存入val形参所指向的变量中 如果出栈失败则返回false 否则返回true
void pop(PSTACK pS,int* pval)
{
if(empty(pS))
{
cout<<"出栈失败!"<<endl;
}
else
{
PNODE r = pS->pTop;
*pval = r->data;
pS->pTop = pS->pTop->pNext;
free(r);
r=NULL;
cout<<"出栈成功,出栈的元素是:"<<*pval<<endl;
}
return;
}
void clear(PSTACK pS)//把有效数据全部删除
{
if(empty(pS)) return;
else
{
PNODE p = pS->pTop;
PNODE q = NULL;
while(p != pS->pBottom)
{
q=p->pNext;
free(p);//free(p)释放的是p所指的对象 不是p
p = q;
}
pS->pTop = pS->pBottom;
return;
}
}
队列
简要介绍
定义:一种可以实现“先进先出”的存储结构
分类:链式队列——用链表实现 静态队列——用数组实现(通常都是循环队列)
循环队列需要几个参数来确定: front rear
1.队列初始化:front和rear的值都是0
2.队列非空:front代表队列最后一个元素 rear代表队列最后一个有效元素的下一个元素
3.队列空:front和rear的值相等 但不一定是零
伪算法演示
入队:将值存入r所代表的位置 r=(r+1)%数组的长度
出队:f=(f+1)%数组的长度
如何判断队列是否已满:
1.多增加一个标识参数
2.少用一个元素 如果r和f的值紧挨着 则队列已满
if ((r+1)%数组长度 == f) 已满;
else 不满;
队列的实现
//该程序可存放的最大整型数数目为5(6-1)
#include<bits/stdc++.h>
using namespace std;
typedef struct Queue
{
int* pBase;
int front;
int rear;
}QUEUE;
void init(QUEUE*);//队列初始化
bool en(QUEUE* ,int val);//入队
bool out(QUEUE* ,int*);//出队
void traverse(QUEUE*);//遍历
bool full(QUEUE*);//判断是否已满
bool empty(QUEUE*);//判断是否为空
int main()
{
QUEUE Q;
int val;
init(&Q);
en(&Q,1);
en(&Q,2);
en(&Q,3);
en(&Q,4);
en(&Q,5);
en(&Q,6);
en(&Q,7);
en(&Q,8);
traverse(&Q);
if(out(&Q,&val))
{
cout<<"出队成功!队列出队的元素是:"<<val<<endl;
}
else cout<<"出队失败!"<<endl;
traverse(&Q);
return 0;
}
void init(QUEUE* pQ)
{
pQ->pBase = (int*)malloc(sizeof(int)*6);
pQ->front = 0;
pQ->rear = 0;
return;
}
bool en(QUEUE* pQ,int val)
{
if(full(pQ)) return 0;
else
{
pQ->pBase[pQ->rear] = val;
pQ->rear = (pQ->rear+1)%6;
return 1;
}
}
bool out(QUEUE* pQ,int* pVal)
{
if(empty(pQ)) return 0;
else
{
*pVal = pQ->pBase[pQ->front];
pQ->front = (pQ->front+1)%6;
return 1;
}
}
void traverse(QUEUE* pQ)
{
int i=pQ->front;
while(i!=pQ->rear)
{
cout<<pQ->pBase[i]<<" ";
i = (i+1)%6;
}
cout<<endl;
return;
}
bool full(QUEUE* pQ)
{
if((pQ->rear+1)%6 == pQ->front) return 1;
else return 0;
}
bool empty(QUEUE* pQ)
{
if(pQ->front == pQ->rear) return 1;
else return 0;
}
递归
简要介绍
定义:一个函数自己直接或间接调用自己
举例
//1.求阶乘
#include<bits/stdc++.h>//for循环实现
using namespace std;
int main()
{
int val,res=1; cin>>val;
for(int i=1;i<=val;i++) res*=i;
cout<<res<<endl;
return 0;
}
#include<bits/stdc++.h>//递归实现
using namespace std;
int f(int n)
{
if(n==1) return 1;
else return f(n-1)*n;
}
int main()
{
int val;cin>>val;
cout<<f(val)<<endl;
return 0;
}
//1+2+...+100
#include<bits/stdc++.h>
using namespace std;
int sum(int n)
{
if(1==n) return 1;
else return n+sum(n-1);
}
int main()
{
cout<<sum(100)<<endl;
return 0;
}
//汉诺塔
#include<bits/stdc++.h>
using namespace std;
void hannuota(int n,char A,char B,char C)//有n个盘子 从A借助B移到C
{
/* 如果是1个盘子
直接将A柱子上的盘子借助C移到B
否则
先将A柱子上的n-1个盘子借助C移到B
直接将A柱子上剩余的一个盘子从A移到C
最后将B柱子上的n-1个盘子借助A移到C
*/
if(n==1) printf("将编号为%d的盘子直接从%c柱子移到%c柱子\n",n,A,C);
else
{
hannuota(n-1,A,C,B);
printf("将编号为%d的盘子直接从%c柱子移到%c柱子\n",n,A,C);
hannuota(n-1,B,A,C);
}
}
int main()
{
int n; cin>>n;
hannuota(n,'A','B','C');
return 0;
}
树
简要介绍
深度:从根节点到最底层节点的层数 根节点是第一层
叶子节点:没有子节点的节点
非终端节点:即非叶子节点
度:子节点的个数
数分类
一般数
二叉树:任意一个节点的子节点个数最多两个,且子节点的位置不可更改
一般二叉树
满二叉树:在不增加树的层数的情况下,无法再多添加一个界定的二叉树称为满二叉树
完全二叉树:如果只是删除了满二叉树最底层最右边的连续若干个节点 这样形成的二叉树就是完全二叉树
森林:n个互不相交的数的集合
树的存储
二叉树的存储
连续存储[完全二叉树]
优点:查找某个节点的父节点和字节点速度很快
缺点:耗用内存空间过大
链式存储
一般树的存储
双亲表示法:求父节点方便
孩子表示法:求子节点方便
双亲孩子表示法
二叉树表示法:把一个普通树转化成二叉树来存储 (一定没有右子树)
具体转换方法:设法保证任意一个节点的做指针指向它的第一个孩子 右指针指向它的下一个兄弟 只要满足此条件 就可以把一个普通树转化成二叉树来存储
森林的存储:先把森林转化为二叉树,再存储二叉树
二叉树操作
遍历
先序遍历 [先访问根节点]:先访问根节点 再先序访问左子树 再先序访问右子树(递归)
中序遍历 [中间访问根节点]:中序遍历左子树 再访问根节点 再中序遍历右子树
后序遍历 [最后访问根节点]:后序遍历左子树 再后序遍历右子树 再访问根节点
已知两种遍历序列求原始二叉树
通过先序和中序 或者 中序和后序可以还原出原始二叉树 但是通过先序和后序是无法还原出原始二叉树的**(必须有中序)**
已知先序和中序求后序
已知中序和后序求先序
链式二叉树遍历具体程序演示
#include<bits/stdc++.h>
using namespace std;
struct BTNode
{
char data;//数据域
struct BTNode* pLchild;//p是指针 L是左 child是孩子
struct BTNode* pRchild;//p是指针 R是右 child是孩子
};
struct BTNode* CreateBTree();
void PreTraverseBTree(struct BTNode*);
void InTraverseBTree(struct BTNode*);
void PostTraverseBTree(struct BTNode*);
int main()
{
struct BTNode* pT = CreateBTree();
PreTraverseBTree(pT);//先序遍历输出
InTraverseBTree(pT); //中序遍历输出
PostTraverseBTree(pT);//后序遍历输出
return 0;
}
struct BTNode* CreateBTree(void)//静态构造树
{
struct BTNode* pA = (struct BTNode*)malloc(sizeof(struct BTNode));
struct BTNode* pB = (struct BTNode*)malloc(sizeof(struct BTNode));
struct BTNode* pC = (struct BTNode*)malloc(sizeof(struct BTNode));
struct BTNode* pD = (struct BTNode*)malloc(sizeof(struct BTNode));
struct BTNode* pE = (struct BTNode*)malloc(sizeof(struct BTNode));
pA->data = 'A';
pB->data = 'B';
pC->data = 'C';
pD->data = 'D';
pE->data = 'E';
pA->pLchild = pB;
pA->pRchild = pC;
pB->pLchild = pB->pRchild = NULL;
pC->pLchild = pD;
pC->pRchild = NULL;
pD->pLchild = NULL;
pD->pRchild = pE;
pE->pLchild = pE->pRchild = NULL;
return pA;
}
void PreTraverseBTree(struct BTNode* pT)
{
if(NULL != pT)
{
cout<<pT->data<<endl;
if(NULL != pT->pLchild) PreTraverseBTree(pT->pLchild);
if(NULL != pT->pRchild) PreTraverseBTree(pT->pRchild);
}
}
void InTraverseBTree(struct BTNode* pT)
{
if(NULL != pT)
{
if(NULL != pT->pLchild) InTraverseBTree(pT->pLchild);
cout<<pT->data<<endl;
if(NULL != pT->pRchild) InTraverseBTree(pT->pRchild);
}
}
void PostTraverseBTree(struct BTNode* pT)
{
if(NULL != pT)
{
if(NULL != pT->pLchild) PostTraverseBTree(pT->pLchild);
if(NULL != pT->pRchild) PostTraverseBTree(pT->pRchild);
cout<<pT->data<<endl;
}
}
查找和排序
快速排序法
#include<bits/stdc++.h>
using namespace std;
void QuickSort(int *a,int low,int high);
int FindPos(int *a,int low,int high);
int main()
{
int a[6] = {2,1,0,5,4,3};
QuickSort(a,0,5);//第二个参数表示第一个元素下标 第三个参数表示最后一个元素下标
for(int i=0;i<6;i++) cout<<a[i]<<" ";//遍历输出
cout<<endl;
return 0;
}
void QuickSort(int *a,int low,int high)
{
int pos;
if(low < high)
{
pos=FindPos(a,low,high);
QuickSort(a,low,pos-1);
QuickSort(a,pos+1,high);
}
}
int FindPos(int *a,int low,int high)
{
int val=a[low];
while(low<high)
{
while(low<high && a[high]>=val) --high;
a[low]=a[high];
while(low<high && a[low]<=val) ++low;
a[high]=a[low];
}//while循环终止后high和low一定是相等的
a[low]=val;
return high;
}