前言

本文是为了总结个人认为的数据结构重点代码(不包括图代码)

顺序表部分

//顺序表结构体定义
#define MaxSize 100
typedef int/char datatype;
typedef struct seqlist{
datatype data[maxsize];
int length;
}seqlist;
  1. 一个顺序表内包涵各类字符串,设计算法把顺序表内的字母元素放在左端,非字母元素放在右端,要求使用当前数据空间且移动次数尽可能少(2023真题)

    //算法思路:定义3个函数,方便调用,is_alpha函数判断输入的data是否为字母元素,swap函数交换输入的两值,主函数move_letters_to_left中负责调整元素
    //1. move_letters_to_left函数中定义left,right分别指向顺序表中第一个元素和最后一个元素
    //2. 当data[left]是字母时,left后移,找到第一个非字母停止,
    //3. right从最后一个元素从后往前扫描,对于data[right]是非字母时,right前移,找到第一个是字母时停止
    //4. 交换 swap(l.data[left], l.data[right]),交换完left后移,right前移
    //5. 重复2,3,4步骤,直到left和right相遇为止
    int is_alpha(char data){
    if ((ch>= 'a' && ch <= 'z' )|| (ch >= 'A' && ch <= 'Z')) {//判断输入字符是否为字母元素
    return 1;
    }
    return 0;
    }

    void swap(datatype &a,datatype &b){//交换两值
    char temp=a;
    a=b;
    b=temp;
    }

    void move_letters_to_left(seqlist &l, int len) {
    int left = 0, right = len-1;
    while (left < right) {//循环结束的时候,字母和非字母就已经完成调整
    if (is_alpha(l.data[left])) {//left位是字母元素,left++
    left++;
    } else if (!isalpha(l.data[right])) {//right上是非字母元素,right--
    right--;
    } else {
    swap(l.data[left], l.data[right]);//当上面if语句走完就已经找到需要交换的元素位置left和right,交换完成后left++,right--,移动指针,继续对比
    left++;
    right--;
    }
    }
    }
  2. 实现顺序表的逆置

    //算法思路:定义两个函数swap与reverse,swap用于交换两值
    //reverse函数中定义两值,i,j分别指向顺序表第一个元素与最后一个元素
    //依次调用swap交换两端元素,交换完成i后移,j前移
    //直到i,j相遇时,顺序表逆置完成.
    void swap(datatype &a,datatype &b){//交换两值
    char temp=a;
    a=b;
    b=temp;
    }
    void reverse(seqlist &l){//逆置
    int i,j;
    i=0,j=l.length-1;
    while(i<j){
    swap(l.data[i],l.data[j]);
    i++;
    j--;
    }
    }
  3. 在一个有序表内插入值为x节点后,表依旧有序(2016年真题)

    //算法思路:先判断当前表的情况 是否为空表或者表满,表满时无法插入,空表时直接插入到第一个后length+1
    //当表内已存在元素时,定义i 依次循环比较data[i]是否大于x,当小于时 i后移,
    //当while循环结束时,此刻找到插入位置i,同时考虑当前i的位置有两种情况1为表内2为表尾,当为表尾时,直接插入表尾后length+1即可,当i位置处于表内时,需将i后元素依次后移一位后插入x,后length+1即可.
    void insertx(seqlist *l,datatype x){
    if (l->length==MaxSize){//表满
    printf("FULL");
    return;
    }
    if (l->size==0){//空表时,直接放入
    l->data[0]=x;
    l.length+=1;
    }
    int i;
    while (i<l->length&&l->data[i]<x){//找到插入位置
    i++;
    }
    if(i<=l->length-1){//当插入位置在表内(0-lenght-1)
    for(int j=l->length-1,j>=i,j--){ //或者j = l->length; j >i ; j-- 则 l->data[j]=l->data[j-1];
    l->data[j+1]=l->data[j];
    }
    l->data[i]=x;
    l->length+=1;
    }else{//插入位置不在当前表中,放入表尾(此刻x大于全表任何元素)
    l->data[l->length]=x;
    l->length+=1;
    }
    }

链表部分

//链表结构体定义
typedef struct Lnode {
int data;
struct Lnode *next;
} Lnode, *LinkList;
  1. 带头节点的单链表,设计函数,求两个单链表的合集,结果用新的链表返回(2013年真题)

    //算法思路:定义p ,q指针,分别指向A B 的第一个数据节点.同时创建合集链表的头节点C,C的尾结点r,定义s指针为元素插入C表准备,
    //当p,q都存在时,先固定p指针不动,将q指针依次后移,当找到与p指针指向元素一致元素时,插入C表,插入后p指针后移,循环往复,
    //直到while循环结束时,合集链表都已经插入完成,此时处理尾结点使其置空 return C函数结束
    linklist merge(Linklist A,Linklist B){
    linklist C=(Lnode*)malloc(sizeof(Lnode));//头节点
    Lnode* r, *s;
    r=C;
    Lnode* p=A->next;
    Lnode* q=B->next;
    while(p){//p存在
    while(q&&q->data!=p->data){//非合集 后移动q
    q=q->next;
    }
    if(q){//是合集元素,插入C表
    s=(Lnode*)malloc(sizeof(Lnode));//创建插入节点
    s->data=q->data;
    r->next=s;//尾插法
    r=s;
    }
    p=p->next;.//往后遍历
    }
    r->next=Null;//处理尾节点
    return C;
    }
  2. 两个带头结点的升序链表合并成一个新的带头节点的升序链表(2022年真题)

    linklist merge(linklist A,linklist B){
    linklist c=(Lnode*)malloc(sizeof(Lnode));
    Lnode*r=c;
    Lnode*p=A->next;
    Lnode*q=B->next;
    while(q&&p){
    if(p->data>q->data){//q<p时
    B->next=q->next;//q节点断链
    r->next=q;//r链接至q
    r=q;//表尾指针后移
    q=B->next;//更新q指针
    }else{//q>p时
    A->next=p->next;//p节点断链
    r->next=p;//r链接至p
    r=p;//表尾指针后移
    p=B->next;//更新p指针
    }
    }
    if(q){//当q不为空时,链接到r
    r->next=q;
    }
    if(p){//当p不为空时,链接到r
    r->next=p;
    }
    free(A);
    free(B);
    return C;

    }
  3. 删除带头节点中的奇数值的节点(2018/2014年真题)

    linklist delodd(linklist &l){
    if(l==null){
    return NULL;
    }
    Lnode*pre=l,p=l->next;
    while(p){
    if(p->data%2==0){//偶数后移动
    pre=p;
    p=p->next;
    }else{//奇数删除
    pre->next=p->next;
    free(p);
    p=pre->next;
    }

    }
    }
  4. 删除不带头节点中的第一个值为x的节点(2015年真题)

    linklist del_x(linklist &l){
    if(l==NULL){
    printf("空表");
    return NULL;
    }
    Lnode*pre=(Lnode*)malloc(sizeof(Lnode));//虚拟头节点
    pre->next=l;//虚拟头结点链接到l
    Lnode*p=pre->next,*s=pre;//p为数据节点,s标识pre是否移动
    while(p&&p->data!=x){
    pre=p;
    p=p->next;
    }
    if(p){//找到值为x的节点
    if(s==pre){//pre未移动表示值为x的节点是第一个数据节点
    l=l->next;//l直接后移一个即可
    }else{//删除值为x的节点
    pre->next=p->next;
    free(p);
    }
    }
    return l;
    }
  5. 求单链表中的节点个数(2016年真题)

    int count(linklist l){//节点是指数据节点
    if(l==head){
    return 0;
    }
    int n=0;
    Lnode*p=l->next;
    while(p){
    n++;
    p=p->next;
    }
    return n;
    }
  6. 不带头节点的单链表是否为升序链表,是返回1,不是返回2(2021年真题)

    int isuporder(linklist l){
    if(l==Null){
    return 0;
    }

    Lnode*pre=l,*p=l->next;
    while(p){
    if(pre->data>p->data){//非升序返回0
    return 0;
    }else{//当前是升序 ,后移
    pre=p;
    p=p->next;
    }
    }//while循环结束时,单链表为升序 返回1
    return 1;
    }
  7. 删除不带头节点head的倒数第m个元素(2023年真题)

    //写法一:虚拟头结点
    linklist del_m(linklist &l){
    if(l==NULL){
    return NULL;
    }
    Lnode*pre=(Lnode*)malloc(sizeof(Lnode));//虚拟头结点
    pre->next=l;
    Lnode*p=pre->next;
    int len=1;
    while(p&&len<=m){//len取0时 len<m ,len取1时 len<=m 否则后移次数对不上
    len++;
    p=p->next;
    }
    if(len<m){
    printf("表长不够");
    return l;
    }
    while(p){
    pre=pre->next;
    p=p->next;
    }
    Lnode*s=pre->next;//pre后一个节点就是倒数第m个元素
    pre->next=s->next;
    free(s);
    return l;
    }
    //写法二
    linklist del_m(linklist &l){
    if(l==NULL){
    return NULL;
    }
    Lnode* pre,*s;
    Lnode*p=l;
    int len=0;
    while(p&&count<m){
    p=p->next;
    len++;
    }
    if(len<m){
    printf("表长不够");
    return l;
    }
    if(p==NULL){//当p在表尾,此刻倒数第m个元素就是表中第一个元素,删除即可
    pre=l;;
    l=l->next;
    free(pre);
    retrun l;
    }
    s=l;
    while(p){//p处于表中
    pre=s;
    s=s->next;
    p=p->next;
    }//删除第m个节点就是当前的s元素
    pre->next=s->next;
    free(s);
    return l;
    }
  8. 一个带头结点的单链表,将奇数移到链表前面,偶数放到后面

    void pation(linklist &l){
    if(l==NULL){
    return;
    }
    Lnode *pre=l,p=pre->next;
    while(p&&p->data%2==1){//奇数后移
    pre=p;
    p=p->next;
    }
    while(p){
    while(p&&p->data%2==0){
    pre=p;
    p=p->next;
    }
    if(p){//偶数后存在奇数时,将其头插到前方
    pre->next=p->next;
    p->next=l->next;//头插法
    head->next=p;
    p=pre->next;//更新p指针
    }
    }

    }

树部分

结构体

//二叉树结构体定义
typedef struct node{
char data;
struct node *lchile,*rchild;
}binode, *binTree;
  1. 3种遍历(递归)

    //前序遍历
    void preOrder(binTree T) {
    if (T != NULL) {
    printf("%d",T->data);
    preOrder(T->lchild);
    preOrder(T->rchild);
    }

    }

    //中序遍历
    void InOrder(binTree T) {
    if (T != NULL) {
    InOrder(T->lchild);
    printf("%d",T->data);
    InOrder(T->rchild);
    }

    }

    //后序遍历
    void PostOrder(binTree T) {
    if (T != NULL) {
    PostOrder(T->lchild);
    PostOrder(T->rchild);
    printf("%d",T->data);

    }

    }
  2. 层次遍历

    //层次遍历借助队列完成 此处提供两种写法 一种为伪代码 另一种为数组队列
    void LevelOrder1(binTree T){//伪代码写法
    if(T==NULL){
    return;
    }
    Queue Q;
    InitQueue(Q);
    binode*p=T;
    Enqueuq(Q,p);
    while(!isempty(Q)){
    Dequeue(Q,p);
    print("%d",p->data);
    if(p->lchild){
    Enqueuq(Q,p->lchild);
    }
    if(p->rchild){
    Enqueuq(Q,p->lchild);
    }
    }

    }

    #define MaxSize 100
    void levelorder2(binTree T){//数组队列方式
    if(T==NULL){
    return;
    }
    binode* queue[MaxSize];
    int front=-1,rear=-1;
    binode*p=T;
    queue[++rear]=p;
    while(front<rear){
    p=queue[++front];
    print("%d",p->data);
    if(p->lchild){
    queue[++rear]=p->lchild;
    }
    if(p->rchild){
    queue[++rear]=p->rchild;
    }
    }

    }
  3. 反转层次遍历

    //算法思路:与层次遍历一致,但是在出队时,不打印元素,而是使其进栈,在完成层次遍历后,依次出栈打印这样打印出来的就是反转的层次遍历
    void ReLevelOrder1(binTree T){//伪代码写法
    if(T==NULL){
    return;
    }
    Queue Q;
    Stack S;
    InitStack(S);
    InitQueue(Q);
    binode*p=T;
    Enqueuq(Q,p);
    while(!isempty(Q)){
    Dequeue(Q,p);
    Push(S,p);
    if(p->lchild){
    Enqueuq(Q,p->lchild);
    }
    if(p->rchild){
    Enqueuq(Q,p->lchild);
    }
    }
    while(!isempty_stack(s)){//栈非空
    Pop(S,p);//出栈打印即是反转层次遍历
    printf("%d",p->data);
    }

    }
  4. 先序非递归/前序非递归

    //非递归遍历借助于栈实现
    void PreOrder(binTree T){//打印顺序为根左右
    Stack S;
    InitStack(S);
    binode*p=T;
    while(p||!isempty(s)){
    if(p!=null){
    print("%d",p->data);//打印节点数据
    Push(S,p);//节点进栈
    p=p->lchild;//遍历左子树
    }else{//左子树进栈完成,转到右子树
    Pop(S,p);
    p=p->rchild;
    }
    }
    }
  5. 中序非递归(2019年真题)

    void InOrder(binTree T){//打印顺序为左根右
    Stack S;
    InitStack(S);
    binode*p=T;
    while(p||!isempty(s)){
    if(p!=null){
    Push(S,p);//节点进栈
    p=p->lchild;//遍历左子树
    }else{
    Pop(S,p);//节点出栈
    print("%d",p->data);//打印节点数据
    p=p->rchild;//遍历右子树
    }
    }
    }
  6. 后序非递归

    void PostOrder(binTree T){//打印顺序为左右根 特殊一些,需要考虑在子树时如何返回到根节点
    Stack S;
    InitStack(S);
    binode*p=T;
    binode*r=NULL;//r负责记录上一个打印的节点位置
    while(p||!isempty(S)){
    if(p!=null){
    Push(S,p);//节点进栈
    p=p->lchild;//遍历左子树
    }else{
    GetTop(S,p);//p为空时,则获取栈顶元素
    if(p->rchlid&&p->rchild!=r){//p有右孩子且未遍历
    p=p->rchild;//p遍历右子树
    }else{//没有右子树或者右子树遍历过
    Pop(S,p);
    print("%d",p->data);//打印节点数据
    r=p;//更新记录节点
    p=NULL;//遍历指针置空
    }
    }
    }

    }
  7. 打印二叉树中x节点的所有祖先,设x的值不超过1个

    //后序遍历中,栈中存放节点的祖先
    void find_x_ancestor(binTree T,int x){
    Stack S;
    InitStack(S);
    binode*p=T;
    binode*r=NULL;//r负责记录上一个打印的节点位置
    while(p||!isempty(S)){
    if(p!=null){
    Push(S,p);//节点进栈
    p=p->lchild;//遍历左子树
    }else{
    GetTop(S,p);//p为空时,则获取栈顶元素
    if(p->rchlid&&p->rchild!=r){//p有右孩子且未遍历
    p=p->rchild;//p遍历右子树
    }else{//没有右子树或者右子树遍历过
    Pop(S,p);
    if(p->data==x){//改写部分-在出栈后判断是否为x,当为x值,当前栈内就是x的祖先元素
    while(!empty(S)){
    Pop(S,p);
    printf("%d",p->data);
    }
    }
    r=p;//更新记录节点
    p=NULL;//遍历指针置空
    }
    }
    }

    }
  8. 求二叉树的高度/深度(递归)

    int depth(binTree T){
    if(T==NULL){
    return 0;
    }
    int ldep,rdep;
    ldep=depth(T->lchild);//ldep统计左子树高度
    rdep=depth(T->rchild);//rdep统计右子树高度
    if(ldep>rdep){//比较左右子树高度,取最大值+1 ,+1为根的高度
    return ldep+1;
    }else{
    return rdep+1;
    }
    }
  9. 非递归求二叉树的高度/深度(2021真题)

    //类层次遍历的思路,当一层最右节点出队时,这层就已经遍历完成,h加一
    #define MaxSize 100
    int high(binTree T){
    if(T==NULL){
    return 0;
    }
    int h=0,last=0;//last指向每层最后一个节点
    binode*Q[MaxSize];//数组队列
    int front=-1,rear=-1;//从-1开始方便对应关系
    binode*p=T;
    Q[++rear]=p;//根进队
    while(front<rear){//队列非空
    p=Q[++front];//出队
    if(p->lchild){
    Q[++rear]=p->lchild;
    }
    if(p->rchild){
    Q[++rear]=p->rchild;
    }
    if(front==last){//当二叉树一层的最右节点出队时
    h++;
    last=rear;//last移动到下一层
    }
    }
    return h;

    }
  10. 求二叉树的单分支节点个数

    int count(binTree T){
    if(T==NULL){
    return 0;
    }
    int n1,n2;
    if((T->lchild==null&&T->rchild)||(T->rchild==null&&T->lchild)){//根为单分支
    n1=count(T->lchild);
    n2=count(T->rchild);
    return n1+n2+1;//额外+1
    }else{
    n1=count(T->lchild);
    n2=count(T->rchild);
    return n1+n2;
    }
    }
  11. 求二叉树双分支节点个数

    int count(binTree T){
    if(T==NULL){
    return 0;
    }
    int n1,n2;
    if(T->lchild&&T->rchild){//根为双分支
    n1=count(T->lchild);
    n2=count(T->rchild);
    return n1+n2+1;//额外+1
    }else{
    n1=count(T->lchild);
    n2=count(T->rchild);
    return n1+n2;
    }
    }
  12. 求二叉树叶子节点个数

    //此处提供两种写法,一种利用全局变量,一种通过返回int
    int n=0;
    void count1(binTree T){
    if(T!=NULL){
    if(T->lchild==null&&T->rchild==null){
    n++;
    }
    count1(T->lchild);
    count1(T->rchild);
    }

    }

    int count2(binTree T){
    if(T==NULL){
    return 0;
    }
    int n1,n2;
    if(T->lchild==null&&T->rchild==null){
    return 1;
    }else{
    n1=count2(T->lchild);
    n2=count2(T->rchild);
    return n1+n2;
    }
    }
  13. 求二叉树是否等价

    int equal(binTree T1,binTree T2){
    int left,right;
    if(T1==NULL&&T2==NULL){//都为空时,等价
    return 1;
    }else if(T1==NULL||T2==NULL){//有一个不为空时,不等价
    return 0;
    }else{//递归比较
    left=equal(T1->lchild,T2->lchild);
    right=equal(T1->rchild,T2->rchild);
    return left&&right;
    }

    }
  14. 交换二叉树左右子树

    void swap(binTree &T){
    if(T!=NULL){
    binode*temp=T->lchild;
    T->lchild=T->rchild;
    T->rchild=temp;
    swap(T->lchild);
    swap(T->rchild);
    }
    }
  15. 查找x节点所在层数

    void search_x_level(bintree T,int x,int level){//level初值为1
    if(T!=NULL){
    if(T->data==x){
    print("x在第%d层",level);
    }
    search_x_level(T->lchild,x,level+1);
    search_x_level(T->rchild,x,level+1);
    }
    }
  16. 求二叉树的宽度(一个树中节点数最多的一层的节点个数)

    //层次遍历改写+level数组统计
    #define MaxSize 100
    void width(bintree T){
    if(T==NULL){
    return 0;
    }
    binode*Q[MaxSize];
    int front=0,rear=0;//队头,队尾
    int level[MaxSize];
    binode*p=T;
    int k=1;//记录层数
    level[rear]=k;//更新level数组
    level[rear]=p;//根进队
    rear++;//更新rear
    while(front<rear){//队列非空
    p=Q[front];
    k=level[front];
    front++;//出队
    if(p->lchild){
    Q[rear]=p->lchild;
    level[rear]=k+1;//新一层
    rear++;//进队
    }
    if(p->rchild){
    Q[rear]=p->rchild;
    level[rear]=k+1;//新一层
    rear++;//进队
    }
    }//level数组已经更新完成
    //eg:123 三个元素构成的二叉树 level应为1 2 2
    //统计宽度
    int max=0,n,i=0;
    k=1;
    while(i<rear){
    n=0;//层数初始化
    while(i<rear&&level[i]==k){//统计每层个数
    n++;
    i++;
    }
    k++;
    if(n>max){
    max=n;//更新节点数
    }
    }
    return max;//返回宽度
    }
  17. 判断二叉树是否为完全二叉树

    //层次遍历全进栈,后判断null后是否全为null
    int iscompete(bintree T){
    if(T==NULL){//空树是完全二叉树
    return 1;
    }
    Queue Q;
    InitQueue(Q);
    binode*p=T;
    Enqueuq(Q,p);
    while(!isempty(Q)){
    Dequeu(Q,p);
    if(p!=NULL){//全进队
    Enqueuq(Q,p->lchild);
    Enqueuq(Q,p->rchild);
    }else{//当出现p==null时,判断后续是否存在null
    while(!empty(Q)){
    Pop(Q,p);
    if(p==null){
    return 0;
    }
    }
    }
    }
    return 1;
    }
  18. 查找前序最后一个节点(样卷考过)

    //递归
    binode* lastnode(binTree T){//前序为根左右顺序,最后一个节点可能出现在根节点,右子树最优,或者左子树最右
    if(T==NULL){
    return NULL;
    }
    if(T->rchild==NULL&&T->lchild==NULL){
    return T;
    }else{
    if(T->rchild){
    return lastnode(T->rchild);
    }else{
    return lastnode(T->lchild);
    }
    }
    }

    //非递归
    binode* lastnode(binTree T){
    binode*p=T;
    if(p){
    while(p->rchild||p->lchild){
    if(p->rchild){
    p=p->rchild;
    }else{
    p=p->rchild;
    }
    }
    }
    return p;
    }
  19. 返回二叉树中序遍历中第一个/最后一个节点

    //中序遍历第一个
    bintree inorder_first(bintree T){//第一个出现在左子树最左,或者根
    if(T&&T->lchild){
    inorder_first(T->lchild);
    }else{
    return T;
    }
    }

    //中序遍历最后一个
    bintree inorder_first(bintree T){//最后一个出现在右子树最右或者根
    if(T&&T->rchild){
    inorder_first(T->rchild);
    }else{
    return T;
    }
    }
​    

​    

​    

线索二叉树

//线索二叉树结构体定义
typedef struct node{
char data;
struct node *lchile,*rchild;
int ltag,rtag;//tag=0表示有孩子,tag=1表示有前驱或后续
}binode, *binTree;

  1. 中序线索二叉树的创建与遍历(中序线索二叉树遍历为2017真题)

    void Inthread(binTree &p,binTree &pre){//创建考的概率不大
    if(p!==NULL){//改写中序遍历
    Inthread(p->lchild);//递归遍历左子树
    if(p->lchild==NULL){//左孩子为空需线索化
    p->lchild=pre;//左孩子指向前驱
    p->ltag=1;//改变标志位
    }
    if(pre&&pre->rchild==NULL){//pre不为空,且右孩子为空需要线索化
    pre->rchild=p;
    pre->rtag=1;
    }
    pre=p;//更新pre位置
    Inthread(p->rchild);//递归遍历右子树
    }
    }


    //中序线索二叉树遍历
    binTree FirstNode(binTree T){//以T为中序遍历的第一个遍历节点
    while(T->ltag==0){//有左孩子指向左孩子
    T=T->lchild;
    }
    return T;//无左孩子则返回其位置
    }

    binTree NextNode(binTree T){//以T为中序遍历的后继
    if(T->rtag==0){//有右孩子,返回右子树的第一个遍历节点
    return FirstNode(T->rchild);
    }else{//无右孩子则其就是后续
    return T->rchild;
    }
    }

    void inorder(binTree T){
    for(binode*p=FirstNode(p);p!=NULL;p=NextNode(p)){
    print("%c",p->data);//打印数据
    }
    }
  2. 先序线索二叉树的创建与遍历

    void prethread(binTree &p,binTree &pre){
    if(p!==NULL){//改写先序遍历
    if(p->lchild==NULL){//左孩子为空需线索化
    p->lchild=pre;//左孩子指向前驱
    p->ltag=1;//改变标志位
    }
    if(pre&&pre->rchild==NULL){//pre不为空,且右孩子为空需要线索化
    pre->rchild=p;//pre节点的右指针指向p
    pre->rtag=1;//改变标志位
    }
    pre=p;//更新pre位置
    if(p->ltag==0){//根已线索化,递归遍历前需判断
    prethread(p->lchild,pre);//左子树未线索化,递归遍历左子树
    }
    if(p->rtag==0){//右子树未线索化
    prethread(p->rchild,pre);//递归遍历左子树
    }

    }
    }


    //先序线索二叉树遍历
    binTree FirstNode(binTree T){//以T为中序遍历的第一个遍历节点
    if(T->ltag==0){//有左孩子指向左孩子
    return T->lchild;
    }else{
    return T->rchild;//无左孩子则指向右孩子或后续
    }

    }

    void preorder(binTree T){
    for(binode*p=T;p!=NULL;p=NextNode(p)){
    print("%c",p->data);//打印数据
    }
    }
  3. 后序线索二叉树的创建

    void PostThread(binTree &p,binTree &pre){
    if(p!==NULL){//改写后序遍历
    PostThread(p->lchild,pre);//递归遍历左子树
    PostThread(p->rchild,pre);//递归遍历右子树
    if(p->lchild==NULL){//左孩子为空需线索化
    p->lchild=pre;//左孩子指向前驱
    p->ltag=1;//改变标志位
    }
    if(pre&&pre->rchild==NULL){//pre不为空,且右孩子为空需要线索化
    pre->rchild=p;//pre节点的右指针指向p
    pre->rtag=1;//改变标志位
    }
    pre=p;//更新pre位置
    }
    }

查找部分

  1. 顺序查找

    int find(int a[],int len,int x){
    for(int i=0,i<len;i++){
    if(a[i]==x){
    return i;
    }
    }
    return 0;
    }
  2. 折半查找

    void mid_search(int a[],int x,int len){
    int low=0,high=len-1;
    while(low<=high){
    int mid=(low+high)/2;
    if(a[mid]==x){
    return mid;//查找成功
    }else if(a[mid]>x){//查找数据在左半表
    high=mid-1;
    }else{//查找数据在右半表
    low=mid+1;
    }
    }
    return 0;//查找失败
    }

    //递归写法
    void mid_search(int a[],int x,int low,int high){
    if(low>high){
    return 0;
    }
    int mid=(low+high)/2;
    if(a[mid]>x){
    return mid_search(a,x,low,mid-1);
    }else if(a[mid]<x){
    return mid_search(a,x,mid+1,high);
    }else{
    return mid;
    }
    }

二叉排序树

//二叉树排序树结构体定义
typedef struct node{
int data;
struct node *lchile,*rchild;
}bsnode, *bstree;
  1. 二叉排序表的创建

    int BST_Insert(bstree &T,int x){
    if(T==NULL){
    T=(bsnode*)malloc(sizeof(bsnode));
    T->data=x;
    T->lchild=NULL;
    T->rchild=NULL;
    return 1;//插入成功
    }else if(T->data==x){//重复不插入
    return 0;
    }else if(T->data>k){//大于k插入右子树
    BST_Insert(T->rchild,int x)
    }else{
    BST_Insert(T->lchild,int x)//小于则插入左子树
    }
    }

    void Creat_BST(bstree &T,int A[],int len){
    T=NULL;
    int i=0;
    while(i<len){
    BST_Insert(T,A[i]);//遍历数组的每一个元素
    i++;
    }
    }

  2. 在二叉排序树中查找值为x的节点

    //非递归
    bsnode* search_x(bstree T,int x){
    while(T!=NULL){
    if(T->data>x){//大于往左找
    T=T->lchild;
    }else if(T->data<x){//小于往右找
    T=T->rchild;
    }else{
    return T;//找到
    }
    }
    return NULL;//没找到
    }

    //递归
    bsnode* search_x(bstree T,int x){
    if(T==NULL){
    return NULL;
    }else{
    if(T->data==x){
    return T;
    }else if(T->data<x){
    return search_x(T->rchild,x);
    }else{
    return search_x(T->lchild,x);
    }
    }
    }
  3. 判断二叉树是否是二叉排序树

    int pre=INI_MIN;//初始定义成一个很小的值,记录上一节点的值
    int JudegBST(bstree T,int &pre){
    int b1,b2;//接收左右子树是否为二叉排序树,是1 否0
    if(T==NULL){//空树是二叉排序树
    return 1;
    }else{
    b1=JudegBST(T->lchild,pre);
    if(b1==0||T->data<=pre){//左子树返回0或者根小于左节点的最大值
    return 0;
    }
    pre=T->data;//更新pre,记录节点数据值
    b2=JudegBST(T->rchild,pre);//判断右子树
    return b2;
    }
    }
  4. 查找给定节点在二叉排序中的层次

    int level(bstree T,binode*p){
    int n=1;
    while(T!=p){
    if(T->data<p->data){//小于去右子树找
    T=T->rchild;
    }else{//大于去右子树找
    T=T->lchild;
    }
    n++;//往下找层数+1
    }
    return n;//返回所在层数
    }
  5. 查找二叉排序树中的最大和最小元素

    int Minkey(bstree T){//最小只可能在左边最左或者根
    while(T->lchild!=NULL){
    T=T->lchild;
    }
    return T->data
    }


    int Maxkey(bstree T){//最小只可能在右边最右或者根
    while(T->rchild!=NULL){
    T=T->rchild;
    }
    return T->data
    }

排序部分

  1. 直接插入排序(重点,两种都考过)

    //顺序存储
    void Insert_Sort(ElemType A[], int len) {
    int i, j;
    for (i = 2; i <= len; ++i) {//遍历数组
    if (A[i - 1] > A[i]) {//遍历元素小于前一个需要寻找插入位置
    A[0] = A[i];//将遍历元素放到A[0]
    for (j = i - 1; A[j] > A[0]; --j) {//寻找待排序元素插入位置
    A[j + 1] = A[j];//将元素后移
    }
    A[j + 1] = A[0];//把待插入元素插入对应位置
    }

    }

    }

    //链式存储
    typedef struct Lnode {
    int data;
    struct Lnode *next;
    } Lnode, *LinkList;

    void linklistsort(LinkList &l){
    if (l->next== NULL){//空表
    return;
    }
    Lnode *pre,*q,*p,*r;//pre和q遍历已排序节点,p和r遍历待排序节点
    p=l->next->next;//后移到第二个数据节点
    l->next->next= NULL;//断链
    while (p){//p不为空时
    pre=l;//初始化pre和q
    q=pre->next;
    while (q!= NULL&&p->data>q->data){//当q<p时,不后移
    pre=q;
    q=q->next;
    }
    r=p->next;//防断链指针
    p->next=q;//插入有序链表中 q刚开始有可能为null,此刻p断链链接到有序序列
    pre->next=p;
    p=r;//更新p指针位置,指向下一个待排序节点
    }
    }
  2. 折半插入排序(代码填空题考过)

    void MidInsertSort(int A[], int n) {
    int i, j, low, high, mid;
    for (i = 2; i <= n; i++) {
    A[0] = A[i];
    low = 1, high = i - 1;//折半查找 找到插入位置 while循环结束时low为插入元素的位置
    while (low <= high) {
    mid = (low + high) / 2;
    if (A[mid] > A[0]) {//左半表
    high = mid - 1;
    } else {//右半表
    low = mid + 1;
    }
    }
    for (j = i - 1; j >=low; --j) {//将插入位置后的元素后移一位
    A[j + 1] = A[j];
    }
    }
    A[low] = A[0];// 插入待排序元素
    }
  3. 希尔排序(要会模拟数组变化状态)

    void ShellSort(ElemType A[], int n) {
    int d, i, j;//d为增量
    for (d= n / 2; d >= 1; d = d / 2) {//步长变化 初试d=n/2,后续减半
    for (i = d + 1; i <= n; i++) {//以d为步长插入排序,核心还是插入排序
    if (A[i] < A[i - d]) {//带排序元素小于上一个元素时需要插入排序
    A[0] = A[i];//待排序元素复制到A[0]
    for (j = i - d; j > 0 && A[0] < A[j]; j = j - d) {//寻找带排序元素插入位置
    A[j + d] = A[j];//比待排序元素大的后移
    }
    A[j + d] = A[0];//插入待排序元素
    }
    }
    }
    }
  4. 快速排序(重点)

    int Partition(int arr[], int low, int high) {
    int pivot = arr[low];//以第一个为基准
    while (low < high) {//low<high时才有比较意义
    while (low < high && arr[high] > pivot) {//从右往左找小于基准的元素
    high--;
    }//while循环结束表示找到arr[high]<pivot的值
    arr[low] = arr[high];//把小于pivot的值移到右边
    while (low < high && arr[low] <= pivot) {//从左往右找大于基准的元素
    low++;
    }//while循环结束表示找到arr[low]>pivot的值
    arr[high] = arr[low];//把大于pivot的值移到左边
    }
    arr[high] = pivot;
    return high;
    }
    void Quicksort(int A[], int low, int high) {
    if (low < high) {
    //分割左侧数组比分割点小,右侧都比分割点大
    int pivot_pos = Partition(A, low, high);
    //分割点前一半,继续分割排序
    Quicksort(A, low, pivot_pos - 1);
    //分割点后一半,继续分割排序
    Quicksort(A, pivot_pos + 1, high);
    }

    }
  5. 简单选择排序

    void swap(int &a, int &b) {//交换两值
    int temp=a;
    a = b;
    b = temp;
    }

    void Select_Sort(ElemType A[], int n) {
    int i, j, min;
    for (i = 0; i < n - 1; i++) {//最多n-1趟
    min = i;//记录遍历过的最小值位置
    for (j = i + 1; j < n; ++j) {//遍历剩余待排序元素
    if (A[j] < A[min]) {
    min = j;//找到最小值下标
    }
    swap(A[i], A[min]);//交换i的位置,即将小值放到前面了
    }
    }

    }
  6. 二路归并排序(不是很重要,要会模拟)

    void Merge(int A[], int low, int mid, int high) {
    int B[N];//辅助数组 降低操作次数
    int i, j, k;
    for (k = low; k <= high; k++) {//A中元素复制到B
    B[k] = A[k];
    }
    for (i = low, j = mid + 1, k = i; i <= mid && j <= high; k++) {
    if (B[i] <= B[j]) {
    //较小值复制到A中
    A[k] = B[i++];//如果相等时,优先放置i指向的元素(保证稳定性)
    } else {
    A[k] = B[j++];
    }
    }
    while (i <= mid) {//存在剩余元素,继续放入
    A[k++] = B[i++];
    }
    while (j <= high) {
    A[k++] = B[j++];
    }
    }
    void MergeSort(int A[], int low, int high) {
    if (low < high) {
    int mid = (low + high) / 2;//分成左右两表
    MergeSort(A, low, mid);//递归排序左表
    MergeSort(A, mid + 1, high);//递归排序右表
    Merge(A, low, mid, high);//全表归并
    }
    }
  7. 冒泡排序

    void swap(int &a, int &b) {//交换两值
    int temp=a;
    a = b;
    b = temp;
    }

    void bubble_swap(int A[], int len) {
    int flag;//记录是否存在交换
    for (int i = 0; i < len - 1; ++i) {//最多进行n-1趟冒泡
    flag = 0;//初始化flag
    for (int j = len - 1; j > i; --j) {//遍历待排序元素进行冒泡
    if (A[j - 1] > A[j]) {
    swap(A[j - 1], A[j]);
    flag = 1;
    }
    }
    if (flag == 0) {//内层循环未发生交换,表示排序已经完成,直接退出排序
    break;
    }
    }
    }


    //双向冒泡
    void double_bubble_swap(int A[], int len) {
    int flag=1;//记录是否存在交换
    int low=0,high=len-1;
    while(low<high&&flag==1){
    flag=0;
    for(int i=low,i<high;i++){
    if(A[i]>A[i+1]){//大的后放
    swap(A[i],A[i+1]);
    flag=1;
    }
    }
    high--;//for循环结束时,定好一个最大值
    for(int j=high,i>low;j--){
    if(A[j]<A[j-1]){//小的前放
    swap(A[j],A[j-1]);
    flag=1;
    }
    }
    low--;//for循环结束时,定好一个最小值
    }
    }
  8. 堆排序(代码填空题考过)

    void swap(int &A, int &B) {//交换两值
    int temp = A;
    A = B;
    B = temp;
    }

    void HeadJust(int A[], int k, int len) {
    A[0] = A[k];//A[0]暂存调整元素
    int i=2*k;//定义i初始化为左孩子位置
    while(i<=n){
    if(i<n&&A[i+1]>A[i]){//右大于左
    i++;//索引到右孩子
    }
    if(A[i]>A[0]){//对比调整元素和较大的孩子的大小
    A[k]=A[i];//孩子值大于调整元素,让孩子来到调整位置
    k=i;//将较大孩子的位置做完下一次循环的调整位置
    i=2*i;//更新索引i为下一次循环调整的左孩子索引
    }else{//当i超过索引值,直接跳出循环,或者无需调整
    break
    }
    }
    A[k] = A[0];//调整元素放入最终位置
    }

    void BuildMaxHeap(ElemType A[], int len) {
    for (int i = len / 2; i > 0; i--) {//从最后一个分支往上调整
    HeadJust(A, i, len);
    }
    }
    void HeapSort(ElemType A[], int len) {
    BuildMaxHeap(A, len);//建大根堆
    for (int i = len; i > 1; i--) {//n-1趟交换
    swap(A[i], A[1]);//交换堆顶和堆底元素,输出堆顶
    HeadJust(A, 1, i - 1);//重新调整
    }

    }