数据结构(严版)课本代码重敲——第九十章

编程笔记 数据结构 第九十章

二叉搜索树

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stack>
using namespace std;
/*
    日期:2018/4/17
    题目:二叉搜索树
*/
typedef int Elemtype;
typedef struct BSTNode
{
    int key;
    Elemtype data;
    struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree;

// 1 创建时插入建立二叉搜索树
void insertBSTree(BSTree &t,BSTree &p)
{

    if (t == NULL)
    {
        t = p; // 根节点为空
    }
    else {
        if (p->data >= t->data)
            insertBSTree(t->rchild,p);
        else
            insertBSTree(t->lchild,p);
    }


}
void createBSTree(BSTree &t)
{
    Elemtype x;
    BSTree p;
    int n ;
    cout<< "请输入N和待排序的数据"<< endl;
    cin >> n;
    for (int i = 0;i<n;i++)
    {
        cin >> x;
        p = (BSTree)malloc(sizeof(BSTNode));
        p->data = x;
        p->key = i+1;
        p->lchild = NULL;
        p->rchild = NULL;
        insertBSTree(t,p);
    }

}
// 中序遍历
void inOrder(BSTree t)
{
    if (t)
    {
       inOrder(t->lchild);
       cout << t->data << " ";
       inOrder(t->rchild);
    }
}

// 查找
int searchBSTree(BSTree &t,Elemtype data)
{
    if (t)
    {
        if (data == t->data)
            return t->key;
        else if (data > t->data)
            searchBSTree(t->rchild,data);
        else
            searchBSTree(t->lchild,data);
    }else
    return 0;
}
// 动态树表:树结构不是一次生成的,而是在查找过程中,当树中不存在关键字等于
// 给定值得结点时再进行插入,新插入的结点一定是叶子结点。

int searchBSTree_dynamic(BSTree t,Elemtype data,BSTree &p,BSTree &f)
{
    if (t)
    {
        if (t->data == data)
        {
            p = t;
            return 1;
        }
        else
        {
            if (t->data > data)
                searchBSTree_dynamic(t->lchild,data,p,t);
            else
                searchBSTree_dynamic(t->rchild,data,p,t);
        }

    }
    else
    {
        p = f;
        return 0;
    }

}
void insertBSTree_dynamic(BSTree &t,Elemtype data)
{
    BSTree p=NULL,f = NULL; // p指向查找到的结点,f为未找到是时的父节点
    BSTree s;
    if (!searchBSTree_dynamic(t,data,p,f))
    {
        s = (BSTree)malloc(sizeof(BSTNode));
        s->data = data;
        s->lchild = NULL;
        s->rchild = NULL;
        // 在树中没找到时即要插入结点
        if (p == NULL)
        {
            t = s; // t为空二叉树,插入的叶子结点即为根节点的特殊情况
        }
        else
        {
            if (data > p->data )
                p->rchild = s;
            else
                p->lchild = s; // 插入新的叶子结点
        }

    }
}

/*
删除节点分为三种情况:
1 p的左右子树均空,直接修改父节点指针
2 p有一个子树,让该子树成为父节点的左子树
3 p的两个子树均不为空
递归找到该结点,然后删除

*/

void deleteBST(BSTree &t,Elemtype data)
{
    void deleteB(BSTree&);
    if (t)
    {
        if (t->data == data)
        {
            deleteB(t);
        }
        else if (t->data > data)
            deleteBST(t->lchild,data);
        else
            deleteBST(t->rchild,data);
    }
}
int deleteB(BSTree &p)
{
    BSTree q,s;
    if (p->lchild == NULL &&p->rchild == NULL)
    {
        q = p;
        p = NULL;
        free(q);
    }
    else
        if (p->lchild == NULL)
        { // 只有左子树空
            q = p;
            p = p->rchild;
            free(q);
        }
        else  // 只有右子树空
        if (p->rchild == NULL)
        {
            q = p;
            p = p->lchild;
            free(q);
        }
        else // 均不空
        {
           s = p->lchild;
           while (s->rchild!=NULL)
                s = s->rchild;
           s ->rchild = p->rchild;
           q = p;
           p = p->lchild;
           free(q);
        }
}
// delete 和 free 的的区别?
int main()
{
    BSTree t = NULL;
    //createBSTree(t);
    int n;
    Elemtype x;
    cout << "n" << endl;
    cin >> n ;
    for (int i=0;i<n;i++)
    {
        cin >> x;
        insertBSTree_dynamic(t,x);
    }
    inOrder(t);
    cout << "请输入要删除的数据" <<endl;
    cin >> x;
    deleteBST(t,x);
    inOrder(t);


    return 0;
}

二叉搜索树的复习

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stack>
using namespace std;
/* 二叉搜索树 复习
1. 创建+插入
2. 搜索
3. 删除
4. 遍历
*/

typedef struct BSTNode
{
    int key;
    struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree;

int insertBSTree(BSTree &t,BSTree &p)
{
    // 如果找到则返回指向关键字的指针,否则插入到树中
    if (t== NULL)
    {
        t = p;
        return 1;
    }else
    {
        if (t->key == p->key)
        {
            return 1;
        }else if (t->key > p->key)
            insertBSTree(t->lchild,p);
        else
            insertBSTree(t->rchild,p);
    }
}
void createBSTree(BSTree &t)
{
    t = NULL;
    int n;
    cout << "请输入N:" <<endl;
    cin >> n;
    cout << "请输入N个数" << endl;
    int key;
    for (int i=0;i<n;i++)
    {
        cin >> key;
        BSTree p = (BSTree)malloc(sizeof(BSTNode));
        p->key = key;
        p->lchild = NULL;
        p->rchild  = NULL;
        insertBSTree(t,p);
    }
}

void preOrder(BSTree T)
{
    if (T)
    {
        preOrder(T->lchild);
        cout << T->key << " ";
        preOrder(T->rchild);
    }
}

void deleteT(BSTree &p)
{
    BSTree q;
    // 删除P指向的结点
    if (p->lchild == NULL && p->rchild == NULL )
    {
        q = p;
        p = NULL;
        free(q);
        return ;
    }
    if (p->lchild == NULL)
    {
        q = p;
        p = p->rchild;
        free(q); // free 和 delete 的区别
        // malloc - free C new - delete C++
    }
    else if (p->rchild == NULL)
    {
        q = p;
        p = p ->lchild;
        free(q);
    }
    else
    {
        // 左右子树均不为空时,P左子树的最右侧的结点+P的右子树
        BSTree s = p->lchild;
        while (s->rchild != NULL)
            s = s->rchild;
        s->rchild = p->rchild;
        q = p;
        p = p->lchild;
        free(q);

    }
}
void deleteBSTNode(BSTree &t,int key)
{
    if (t)
    {
        // t为空时则为未找到
        if (t->key == key)
            deleteT(t);
        else if (t->key > key)
            deleteBSTNode(t->lchild,key);
        else
            deleteBSTNode(t->rchild,key);
    }

}
int main()
{
    BSTree t;
    createBSTree(t);
    preOrder(t);
    cout << "key:" << endl;
    int key;
    cin >> key;
    deleteBSTNode(t,key);
    preOrder(t);


    return 0;
}

哈希表的实现

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stack>
#define SUCCESS 1
#define UNSUCCESS -1
#define NULLkey -65519


using namespace std;
/*
哈希表
*/
const int HashLength = 20;
typedef int Elemtype;
typedef struct
{
    Elemtype *elem;
    int count; // 当前元素个数
}HashTable;

void initHashTable(HashTable &h)
{
    h.elem = (Elemtype *)malloc(sizeof(Elemtype)*HashLength);
    h.count = 0;
    for (int i = 0;i<HashLength;i++)
        h.elem[i] = NULLkey;
}

int hash_f(int key)
{
    return key%HashLength;
}
void insertHashTable(HashTable &h,int key)
{
    int addr = hash_f(key);
    while (h.elem[addr]!= NULLkey)
    {
        addr = (addr+1)%HashLength;
    }
    h.elem[addr] = key;
    h.count++;
}
int searchHashTable(HashTable h,int key)
{
    // 查找成功返回存储位置否则返回UNSUCCESS
    int addr = hash_f(key);
    while (h.elem[addr]!=key)
    {
        addr = (addr+1)%HashLength;
        if (h.elem[addr] == NULLkey || addr == hash_f(key))
            return UNSUCCESS;
        // 如果线性探测再散列到NULLKEY或者转了一圈重新回到起点则没找到
    }

    return addr;
}
int main()
{
    int a[] = {14,1,68,27,55,19,20,84,79,23,11,10};
    HashTable h;
    initHashTable(h);
    for (int i = 0;i<12;i++ )
        insertHashTable(h,a[i]);
    for (int i=0;i<12;i++)
    {
        int addr = searchHashTable(h,a[i]);
        cout << a[i] << " : " << addr << endl;
    }


    return 0;
}

排序

分类:
1 插入类
- 直接插入
- 折半插入
- 希尔排序
2 交换类
- 冒泡排序
- 快速排序
3 选择排序
- 简单选择排序
- 堆排序
4 归并类
- 归并排序
5 基数排序

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stack>
#define SUCCESS 1
#define UNSUCCESS -1
#define NULLkey = -65519


using namespace std;
/*
排序
*/
// 直接插入排序:每次都是在一个有序的序列中插入一个新的关键字
void insertSort(int r[],int n) // 待排序关键字存储在1-n的位置
{
    /*
    时间复杂度:
    1 最好情况:仅有外层循环 O(n)
    2 最坏情况:n*(n-1)/2 O(n^2)
    空间复杂度:
    辅助存储空间仅有temp,故为O(1)
    */
    int temp;
    for (int i=1;i<=n;i++)
    {
        temp = r[i];// 存放待插入关键字
        int j = i-1;
        while (r[j] > temp && j > 0)
        {
            r[j+1] = r[j];
            j--;
        }
        r[j+1] = temp;

    }
}

void binsertSort(int r[],int n)
{
    /*
    和直接插入排序的区别是:查找插入位置所花的时间大大减小
    */
    for (int i=1;i<=n;i++) // i = 1 时已经为有序数列
    {
        r[0] = r[i] ; // r[0] 空余空间中存放当前待插入关键字
        int low = 1,high = i-1; // 当前的有序序列为1-i-1;
        while (low <= high)
        {
            int mid = (low + high)/2;
            if (r[mid] >= r[0])
            {
                high = mid-1;
            }
            else
                low = mid+1;
        }
        // 之所以让low = high时再进入循环:比较当前关键字和high/low指向关键字的大小
        // 离开循环时low = high+1,low指向位置即为待移动的位置
        for (int j=i-1;j>=low;j--)
            r[j+1] = r[j];
        r[low] = r[0];

    }
}
// 希尔排序
void shellInsert(int r[],int n,int dlta)
{
    int j;
    for (int i = 1+dlta; i<=n ; i++)
    { // 循环 n - 1 - dlta 次 = 子序列的个数
        if (r[i] < r[i-dlta])
        {
            r[0] = r[i];
            for (j = i-dlta ; j>0 && r[j] > r[0] ; j = j-dlta )
                r[j+dlta] = r[j];
            r[j+dlta] = r[0];
        }
    }
}
void shellSort(int r[],int dlta[],int n,int t )
{
    /*
    缩小增量排序:对r[n]进行增量为dlta[t]的排序过程
    思想:直接插入排序适合基本有序的序列,希尔排序的每趟排序都会使整个序列变得更加有序,
    等整个序列基本有序后,最后进行一趟直接插入排序,效率会更高。
    注意:1.希尔排序是不稳定的。
    2.增量序列的最后一个值一定取1,增量序列中的值尽量没有除1之外的公因子
    */
    for (int i = 0;i<t;i++)
    {
        shellInsert(r,n,dlta[i]);
    }
}
void bubbleSort(int r[],int n)
{
    /*
    外层比较n-1次,内层比较n-i次
    时间复杂度:O(N^2)
    空间复杂度:O(1)
    */
    int flag;
    for (int i = 1;i<n;i++)
    {
        flag = true;
        for (int j = 1;j<=n-i;j++)
        {
            if (r[j] > r[j+1])
            {
                int temp = r[j];
                r[j] = r[j+1];
                r[j+1] = temp;
                flag = false;
            }
        }
        if (flag) // 没发生交换说明有序
            break;
    }
}
// 快速排序之合并版
/*
通常,快速排序是同量级O(nlogn)的排序方法中,平均性能最好。
但若初始记录序列按关键字有序或基本有序时,快速排序将退化为起泡排序。
空间复杂度:栈
*/
void quickSort(int r[],int low,int high)
{
    int i = low,j = high;
    if (low < high)
    {
        while (i<j)
        {
            r[0] = r[low];//枢纽
            while (r[j]>r[0] && i < j)
                j -- ;
            if (i < j)
            {
                // 此时r[j] < r[0] 交换
                r[i] = r[j];
                i++;
            }
            while (i < j && r[i] < r[0] )
                i++;
            if (i<j)
            {
                r[j] = r[i];
                j--;
            }
        }
        r[i] = r[0];// 将枢纽定在最终位置
        quickSort(r,low,i-1);
        quickSort(r,j+1,high);
    }
}

// 快速排序之分离版
int Partition(int r[],int low,int high)
{
    while (low<high)
    {
        r[0] = r[low];
        while (low < high && r[high] > r[0]  )
            high -- ;
        if (low < high)
        {
            r[low] = r[high];
            low++;
        }
        while (low<high && r[low] < r[0])
            low++;
        if (low <high)
        {
            r[high] = r[low];
            high--;
        }
    }
    r[low] = r[0];
    return r[0];
}
void qsort(int r[],int low,int high)
{
    if (low < high)
    {
        int flag = Partition(r,low,high); // 一分为二并得到枢纽
        qsort(r,low,flag -1);
        qsort(r,flag+1,high);
    }
}
void print(int r[],int n)
{
    for (int i=1;i<=n;i++)
        cout << r[i] <<' ';
    cout << endl;
}
// 简单选择排序
void selectSort(int r[],int n)
{
    int i,j,k;
    for (i=1;i<=n-1;i++)
    {
        k = i;
        for (j=i;j<=n;j++)
        {
            if (r[j]<r[k])
            {
                k = j;
            }
        }
        if (k!=i)
        {
            r[0] = r[i];
            r[i] = r[k];
            r[k] = r[0];
        }
    }
}
/*
堆排序:定义:非叶子结点的值都不大于(或不小于)其左右孩子结点的值。
将无序序列调整为完全二叉树形式的堆,根节点为最大值或最小值。
通过堆找到最大最小值后放在队列的尾部,将无序队列调整为有序队列。

执行过程:
1 层次遍历法建立初始堆,找到第一个非叶子结点,按照从右往左,从下往上的顺序,
依次判断是否满足堆定义(假设为大顶堆,即孩子结点的数值是否都小于根节点)。
如不满足则选择孩子中较大的结点和根节点交换,同时判断下移的根节点的值是否满足定义。
2 将当前无序序列的第一个值和最后一个值交换,有序序列中增加一个值。判断和根节点交换的
新节点是否满足堆定义并进行调整。

时间复杂度:
*/
void shift(int r[],int low,int high)
{
    int temp = r[low];
    int i = low,j = 2*i;
    while (j<=high)
    {
        if (j<high && r[j] < r[j+1])
        {
            j = j+1; // 选择I节点的孩子中较大的一个
        }
        if (temp < r[j])
        {
            r[i] = r[j];
            i = j;
            j = j*2;
        }
        else
            break;
    }
    r[i] = temp;
}
void heapSort(int r[],int n)
{
    // 1. 找到最后一个非终端节点,从右向左,从下向上进行调整,建立初始堆
    int i;
    for (i = n/2; i >=1 ;i--)
    {
        shift(r,i,n);
    }
    // 2. 将一次调整后的最大值和无序序列的最后一个值交换
    for (i = n;i>=2;i--) // 进行n-1次排序
    {
        r[0] = r[1];
        r[1] = r[i];// r[i]为最后一个
        r[i] = r[0];
        shift(r,1,i-1);//在减小了一个关键字的无序序列中进行调整
    }

}
int main()
{
    int n ;
    cin >> n;
    int r[n];
    for (int i=1;i<=n;i++)
        cin >>r[i];
    //insertSort(r,n);
    //binsertSort(r,n);
//    bubbleSort(r,n);
    //quickSort(r,1,n);
//    selectSort(r,n);
heapSort(r,n);
    print(r,n);




    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_33846054/article/details/80036373
今日推荐