HNU数据结构与算法szh

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; 
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10Futari

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值