数据结构/数据结构与算法实验四 二叉排序树与快速排序(查找与排序算法的实现)

简介: 数据结构/数据结构与算法实验四 二叉排序树与快速排序(查找与排序算法的实现)

1.实验题目

1.已知二叉树T的结点形式为(lchild、data、count、rchild),其中count为查找次数计数。在树中查找值为X的结点,若找到则该结点的count加1,函数返回值为TRUE;否则,作为一个新结点插入树中,插入后仍为二叉排序树,且函数返回值为FALSE。写出其非递归算法(迭代算法)。(教材P310,习题八的“四、应用题”的第10题。)

2.验证快速排序的递归算法。

3.利用快速排序的思想编写算法,对关键字取值为整数的一个数据元素序列进行整理,使所有关键字为负值的数据元素排在关键字为非负值的数据元素之前。

2.实验要求

查找实验要求实现以下功能:

1.对从键盘输入的顺序任意的若干个正整数建立一棵二叉排序树,以-1作为结束。

2.先给出二叉排序树的先序、中序和后序遍历结果,然后从键盘输入一个整数,在二叉排序树中删除该整数,并给出是否删除成功的结果,若删除成功,则再给出删除后的二叉排序树的先序、中序和后序遍历结果。

3.先给出二叉排序树的先序、中序和后序遍历结果,然后从键盘输入一个整数,调用实现“二、实验题目”的功能。根据函数调用结果,显示查找成功的该结点的count值,或者是给出插入新的结点后的二叉排序树的先序、中序和后序遍历结果。

排序实验要求:

1.对从键盘输入的任意个整数,通过递归快速排序使之成为有序的序列,输出每一趟排序的结果。

2.对从键盘输入的任意个整数,按照“1.实验题目”的第1小题的要求输出结果。

3.算法思路

1.建立二叉排序树

在主程序中运用while语句输入一行数据,以-1为终止。输入时,调用二叉排序树的插入函数。插入函数的逻辑如下:先查找该数,若找到则插入失败。若未找到则插入。插入时,若该树为空树,则创建根结点。若该树不为空树,则在相应位置创建含有所需数据的结点。

2.遍历二叉排序树

先序、中序、后序遍历二叉树。先序遍历二叉排序树时,先访问当前结点,再先序遍历左子树,最后先序遍历右子树。中序遍历二叉排序树时,先中序遍历左子树,再访问根结点,最后中序遍历右子树。后序遍历二叉排序树时,先后序遍历左子树,再后序遍历右子树,最后访问根结点。

3.删除节点

先查找要删除的点p。若查找成功,则调用删除算法,删除成功。若查找失败,则删除也失败。删除时,从根结点开始重新查找该结点。若p的数据比当前访问的结点的数据小,则在左子树上删除p点。若p的数据比当前访问的结点的数据大,则在右子树上删除p点。若找到了p结点,则判断其有没有左子树或右子树。若其没有左子树也没有右子树,则是个叶结点,直接删除。若只有右子树但没有左子树,则将点p替换成右子树上第一个结点。若其只有左子树但没有右子树,则将p替换成左子树上第一个结点。若其不仅有右子树而且有左子树,则找到其右子树上最左的结点s,将s替换p,并删掉s结点。

4.查找并记录访问次数

在设计类时,结点除了数据域、指针域,还有一个count域记录结点被访问的次数。利用迭代法,通过循环的终止条件控制是否找到p点。若没找到p点,则调用插入结点的算法。若找到p点,则count增加1。

5.利用快速排序的思想将负数排在正数前

在快速排序的算法中,我们将数组第一个元素作为基准,将数组划分成比基准小、比基准大两个部分。在这个算法中,我们以0而非数组第一个元素作为基准元素,便可以将比0小的数排在比0大的数之前。我们仍然用e=elem[low]这一语句记录数组第一个元素,但这个元素不是基准,而是在i和j指针“撞”在一起的位置上将这个元素放回。无论第一个元素正负,结果上都会是前面是负数,后面是非负数。

4.输出演示

数据的输入

先序遍历

中序遍历

后序遍历

删除数据(删除失败)

删除数据(删除成功)

删除成功后的遍历序列

查找成功

查找失败,插入成功

5.源代码

题目1

binarySortTree.h

#pragma once
#include"binTreeNode.h"
#include<Windows.h>
#include<iostream>
using namespace std;
template <class elemtype>
class binarySortTree
{
private:
  binTreeNode<elemtype>* root;
public:
  bool isEmpty() {//判空
    return root == NULL;
  }
  binTreeNode<elemtype>* find(const elemtype& key, binTreeNode<elemtype>*& f) const{
    //从f结点开始向下查找值为key的结点
    binTreeNode<elemtype>* p=root;
    f = NULL;//初始化
    while (p != NULL && p->data != key) {//往下搜索
      if (key < p->data) {
        f = p;
        p = p->lchild;
      }
      else {
        f = p;
        p = p->rchild;
      }
    }
    return p;//若数值不存在,则指向NULL结点被返回
  }
  void preOrder(binTreeNode<elemtype>* r) const {//先序遍历
    if (r != NULL) {
      cout << r->getData()<<" ";
      preOrder(r->lchild);
      preOrder(r->rchild);
    }
  }
  void inOrder(binTreeNode<elemtype>* r) const {//中序遍历
    if (r != NULL) {
      inOrder(r->lchild);
      cout << r->getData()<<" ";
      inOrder(r->rchild);
    }
  }
  void postOrder(binTreeNode<elemtype>* r) const {//后序遍历
    if (r != NULL) {
      postOrder(r->lchild);
      postOrder(r->rchild);
      cout << r->getData()<<" ";
    }
  }
  bool append(const elemtype& e) {
    //为平衡二叉树添加一个新的结点
    binTreeNode<elemtype>* f=NULL;//指向被查找结点双亲
    if (find(e, f) == NULL) {//查找失败,插入成功
      binTreeNode<elemtype>* p;
      p = new binTreeNode<elemtype>(e);
      if (isEmpty())//若树是空树
        root = p;
      else if (e < f->data)//若不是空树,则插入到相应位置上
        f->lchild = p;
      else
        f->rchild = p;
      return true;
    }
    else
      return false;//查找成功,不能插入数值重复的结点,插入失败
  }
  void Delete(const elemtype& k, binTreeNode<elemtype>*& p) {
    //在p为根的二叉排序树上删除关键字为k的结点
    binTreeNode<elemtype>* s, * temp;
    if (p != NULL)
      if (k < p->data)//还没找到p
        Delete(k, p->lchild);//递归地在p的左子树上删除关键字为k的结点
      else if (k > p->data)
        Delete(k, p->rchild);//递归地在p的左子树上删除关键字为k的结点
      else if (p->lchild != NULL && p->rchild != NULL){//找到p,但是p的左右子树都不空 
        //s = Min(p->rchild);
        temp = p->rchild;
        while (temp->lchild != NULL) {
          temp = temp->lchild;
        }//找到p的右子树上最小的数s,替换掉p,然后删掉s
        s = temp;
        p->data = s->data;//将p替换成s
        Delete(s->data, p->rchild);//递归地删掉s
      }
      else {//相等找到,但是左或右为空
        temp = p;
        if (p->lchild == NULL)       p = p->rchild;//左子树空,则将p替换为右子树上第一个结点
        else if (p->rchild == NULL)  p = p->lchild;//右子树空,则将p替换为左子树上第一个结点
        delete temp;
      }
  }
  bool t2(int val){//第二题:先查找,查找成功则删除成功,查找失败则删除失败
    binTreeNode<elemtype>* f = NULL;
    binTreeNode<elemtype>* p = find(val, f);
    if (p == NULL) {
      //查找失败,删除失败
      cout << "删除失败!";
      return false;
    }
    else {
      //查找成功,删除成功
      //deleteNode(p);
      Delete(val, root);
      cout << "\n删除成功!";
      return true;
    }
  }
  bool t3(int key) {//第三题:先查找,查找成功则计数,查找失败则插入
    binTreeNode<elemtype>* p=root,*f = root;
    f = NULL;//f为要找的结点的双亲结点
    while (p != NULL && p->data != key) {//利用迭代法查找
      if (key < p->data) {
        f = p;
        p = p->lchild;
      }
      else {
        f = p;
        p = p->rchild;
      }
    }
    if (p != NULL) {//查找成功
      p->count++;//访问到了p结点,则p的被访问次数需要计数
      cout << "查找成功!";
      return true;
    }
    else {//查找到最后查找失败时,若数据比双亲结点的数小,则说明双亲结点左子树为空
      //若数据比双亲结点的数大,则说明双亲结点右子树为空
      cout << "查找失败!正在插入该结点";
      if(root==NULL)
        root= new binTreeNode<elemtype>(key);//若为空树,则需要创建一个根结点
      else {//在相应位置上创建新的结点,并且查找失败
        if (key > f->data)
          f->rchild = new binTreeNode<elemtype>(key);
        else
          f->lchild = new binTreeNode<elemtype>(key);
      }
      return false;
    }
  }
  binTreeNode<elemtype>* getRoot() {
    return this->root;
  }
  binarySortTree() {
    root = NULL;//默认的无参构造函数
  }
};

binTreeNode.h

#pragma once
#include<Windows.h>
template<class elemtype>
struct binTreeNode
{
  elemtype data;
  int count;//结点被访问次数
  binTreeNode<elemtype>* lchild;
  binTreeNode<elemtype>* rchild;
  binTreeNode(elemtype mdata = 0) {//构造函数,接受无参数构造
    count = 0;
    data = mdata;
    lchild = NULL;
    rchild = NULL;
  }
  int getcount() {
    return count;
  }
  elemtype getData() {
    return data;
  }
};

main.cpp

#include<iostream>
#include"binarySortTree.h"
using namespace std;
int main() {
  int num;//利用num变量输入数字
  int fun;//选择功能
  int val;//删除或插入数据时输入
  binarySortTree<int> bintree;
  cout << "请输入数据,以-1为终止";
  cin >> num;
  while (num != -1) {//输入数据,以-1为终止
    bintree.append(num);
    cin >> num;
  }
  binTreeNode<int>* p=NULL;//工作指针
  binTreeNode<int>* root=bintree.getRoot(),*mroot = bintree.getRoot();//根结点
  do{
    cout << "\n请选择你想要使用的功能:\n";
    cout << "1.先序遍历\n2.中序遍历\n3.后序遍历\n4.删除数据\n5.查找数据\n6.退出";
    cin >> fun;
    switch (fun) {
    case 1:
      cout << "先序遍历序列为:";
      bintree.preOrder(root);
      break;
    case 2:
      cout << "\n中序遍历序列为:";
      bintree.inOrder(root);
      break;
    case 3:
      cout << "\n后序遍历序列为:";
      bintree.postOrder(root);
      break;
    case 4:
      cout << "\n请输入你想删除的数字:";
      cin >> val;
      bintree.t2(val);
      break;
    case 5:
      cout << "\n请输入你要插入或查找的数字:";
      cin >> val;
      if (bintree.t3(val)) {//调用题3中用迭代实现的函数
        mroot = root;
        p=bintree.find(val,mroot);//find函数中的参数是取引用调用,所以根结点地址需要在调用函数前重置
        cout <<"这个节点已被访问次数"<< p->getcount();//函数只要返回查找成功或失败而不自带输出访问次数的功能
      }
      else {
        cout << "自动显示遍历结果!";
        cout << "\n先序遍历序列为:";
        bintree.preOrder(root);
        cout << "\n中序遍历序列为:";
        bintree.inOrder(root);
        cout << "\n后序遍历序列为:";
        bintree.postOrder(root);
      }
      break;
    default:break;
    }
  } while (fun != 6);//输入6以退出
  cout << "\n运行完成!";

第二题

main.cpp

#include<iostream>
#include<stdio.h>
using namespace std;
int times = 0;//全局变量,记录是第几次排序
int n = 0;//全局变量,记录数组长度
template<class elemtype>
void quicksort(elemtype elem[], int low, int high) {
  elemtype e = elem[low];
  int i = low, j = high;
  while (i < j) {
    while (i < j && elem[j] >= e)j--;
    if (i < j) elem[i++] = elem[j];
    while (i < j && elem[i] <= e) i++;
    if (i < j) elem[j--] = elem[i];
  }
  elem[i] = e;
  times++;
  printf("第%d次排列的结果为:", times);
  for (int t = 0; t < n; t++)
    cout << elem[t] << " ";
  cout << endl;//在递归进入下一层排序前先输出本次排序结果
  if (low < i - 1) quicksort(elem, low, i - 1);
  if (i + 1 < high)quicksort(elem, i + 1, high);
}
template<class elemtype>
void findNegative(elemtype elem[], int n) {
  elemtype e = elem[0];
  int i = 0, j =n-1;
  while (i < j) {
    while (i < j && elem[j] >= 0)j--;
    if (i < j) elem[i++] = elem[j];
    while (i < j && elem[i] <0) i++;
    if (i < j) elem[j--] = elem[i];
  }//寻找负数的思想与快速排序类似
  //快速排序中将数字与第一个数比
  //这里将数字与0比
  //最后无论第一个数的大小都要将第一个数放到对应位置。
  elem[i] = e;
  //算法已经结束,没有递归的后续过程
}
int main() {
  cout << "请输入数组中数的个数:\n";
  cin >> n;
  int *arr=new int[n];
  cout << "请输入数据:";
  for (int i = 0; i < n; i++)
    cin >> arr[i];
  int func,low,high;
  cout << "请选择功能:";
  cout << "1.快速排序";
  cout << "2.将负数整理在非负数前";
  cin >> func;
  switch (func) {
    case 1:
      low = 0;
      high = n - 1;
      quicksort(arr, low, high);
      break;
    case 2:
      findNegative(arr, n);
      break;
  }
  for (int i = 0; i < n; i++)
    cout << arr[i]<<" ";
}


目录
相关文章
|
4月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
106 1
|
4月前
|
存储 搜索推荐 算法
加密算法、排序算法、字符串处理及搜索算法详解
本文涵盖四大类核心技术知识。加密算法部分介绍了对称加密(如 AES)、非对称加密(如 RSA)、哈希摘要(如 SHA-2)、签名算法的特点及密码存储方案(加盐、BCrypt 等)。 排序算法部分分类讲解了比较排序(冒泡、选择、插入、归并、快排、堆排序)和非比较排序(计数、桶、基数排序)的时间复杂度、适用场景及实现思路,强调混合排序的工业应用。 字符串处理部分包括字符串反转的双指针法,及项目中用正则进行表单校验、网页爬取、日志处理的实例。 搜索算法部分详解了二分查找的实现(双指针与中间索引计算)和回溯算法的概念(递归 + 剪枝),以 N 皇后问题为例说明回溯应用。内容全面覆盖算法原理与实践
162 0
|
4月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
118 0
|
12月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
475 1
|
8月前
|
存储 算法 Java
算法系列之数据结构-二叉树
树是一种重要的非线性数据结构,广泛应用于各种算法和应用中。本文介绍了树的基本概念、常见类型(如二叉树、满二叉树、完全二叉树、平衡二叉树、B树等)及其在Java中的实现。通过递归方法实现了二叉树的前序、中序、后序和层次遍历,并展示了具体的代码示例和运行结果。掌握树结构有助于提高编程能力,优化算法设计。
232 10
 算法系列之数据结构-二叉树
|
9月前
|
存储 搜索推荐 算法
算法系列之排序算法-堆排序
堆排序(Heap Sort)是一种基于堆数据结构的比较排序算法。它的时间复杂度为 $O(nlogn)$,并且是一种原地排序算法(即不需要额外的存储空间)。堆排序的核心思想是利用堆的性质来维护一个最大堆或最小堆,然后逐步将堆顶元素(最大值或最小值)取出,放到数组的末尾,最终得到一个有序的数组。
212 8
算法系列之排序算法-堆排序
|
8月前
|
算法 Java
算法系列之数据结构-Huffman树
Huffman树(哈夫曼树)又称最优二叉树,是一种带权路径长度最短的二叉树,常用于信息传输、数据压缩等方面。它的构造基于字符出现的频率,通过将频率较低的字符组合在一起,最终形成一棵树。在Huffman树中,每个叶节点代表一个字符,而每个字符的编码则是从根节点到叶节点的路径所对应的二进制序列。
188 3
 算法系列之数据结构-Huffman树
|
8月前
|
算法 Java
算法系列之数据结构-二叉搜索树
二叉查找树(Binary Search Tree,简称BST)是一种常用的数据结构,它能够高效地进行查找、插入和删除操作。二叉查找树的特点是,对于树中的每个节点,其左子树中的所有节点都小于该节点,而右子树中的所有节点都大于该节点。
266 22
|
8月前
|
JavaScript 前端开发 算法
JavaScript 中通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能,JS中排序算法的使用详解(附实际应用代码)
Array.sort() 是一个功能强大的方法,通过自定义的比较函数,可以处理各种复杂的排序逻辑。无论是简单的数字排序,还是多字段、嵌套对象、分组排序等高级应用,Array.sort() 都能胜任。同时,通过性能优化技巧(如映射排序)和结合其他数组方法(如 reduce),Array.sort() 可以用来实现高效的数据处理逻辑。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
9月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
250 30

热门文章

最新文章