408数据结构C语言代码
本文最后更新于 282 天前,如有失效请评论区留言。

第二章 线性表

线性表的基本操作

  InitList(&L): 初始化表。构建一个空线性表L,分配内存空间
  DestroyList(&L): 销毁操作。销毁线性表,并释放线性表L所占用的内存空间
  ListInsert(&L,i,e): 插入操作。在表L中的第i个位置插入指定元素e
  ListDelete(&L,i,&e): 删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值
  LocateElem(L,e): 按值查找操作。在表L中查找具有给定关键字值的元素
  GetElem(L,i): 按位查找操作。获取表L中第i个位置的元素的值
  其他常用操作:
  Length(L): 求表长。返回线性表L的长度,即L中数据元素的个数
  PrintList(L): 输出操作。按前后顺序输出线性表L的所有元素值
  Empty(): 判空操作。若L为空表,则返回true,否则返回false

顺序表的定义

静态分配

#include <stdio.h>
  #define MaxSize 10       //定义最大长度
  typedef struct{
      ElemType data[MaxSize];    //用静态的“数组”存放数据元素
      int length;    //顺序表的当前长度
  }SeqList;    //顺序表的类型定义(静态分配方式)
  //基本操作——初始化一个顺序表
  void InitList(SqList &L){
      for(int i=0; i<MaxSize; i++)   
          L.data[i]=0;    //将所有数据元素设置为默认初始值
      L.length=0;    //顺序表初试长度为0
  }        
  int main(){
      SeqList L;    //声明一个顺序表
      InitList(L);    //初始化顺序表
      ......
      return 0;
  }

动态分配

#include <stdlib.h>
  #define InitSize 10    //默认的最大长度
  typedef struct{
      int *data;    //指示动态分配数组的指针
      int MaxSize;    //顺序表的最大容量
      int length;    //顺序表的当前长度
  }SeqList;
  void InitList(SeqList &L){
      //用 malloc 函数申请一片连续的存储空间
      L.data = (int *)malloc(InitSize*sizeof(int));
      L.length = 0;
      L.MaxSize = InitSize;
  }
  //增加动态数组的长度
  void IncreaseSize(SeqList &L, int len){
      int *p = L.data;
      L.data = (int *)malloc((L.MaxSize+len)*sizeof(int));
      for(int i=0; i<L.length; i++){
          L.data[i] = p[i];    //将数据复制到新区域
      }
      L.MaxSize = L.MaxSize+len;    //顺序表最大长度增加 len
      free(p);    //释放原来的内存空间
  }
  int main(){
      SeqList L;    //声明一个顺序表
      InitList (L);    //初始化顺序表
      ...... 
      IncreaseSize(L,5);
      return 0;
  }

顺序表的基本操作

插入操作

#define MaxSize 10    //定义最大长度
  typeof struct{
      int data[MaxSize];    //用静态“数组”存放数据元素
      int length;    //顺序表的当前长度
  }SeqList;    //顺序表的类型定义
  bool ListInsert(SeqList &L,int i,int e){
      if(i<1 || i>L.length+1)    //判断i的范围是否有效
          return false;
      if(L.length >= MaxSize)    //当前存储空间已满,不能插入
          return false;
      for(int i=L.length; j>=i; j--)    //将第i个元素及之后的元素后移
          L.data[j] = L.data[j-1];
      L.data[i-1]=e;    //在第i个位置放入e
      L.length++;    //长度加1
      return true;
  }

删除操作

bool ListDelete(SeqLizt &L,int i,int &e){
      if(i<1 || i>L.length)    //判断i的范围是否有效
          return false;   
      e = L.data[i-1];    //将被删除的元素赋给e
      for(int j=i; j<L.length; j++)    //将第i个位置后的元素前移
          L.data[j-1] = L.data[j];
      L.length--;    //线性表长度-1
      return true;
  }
  int main(){
      SeqList L;
      InitList(L);
      ......
      int e = -1;
      if (ListDelete(L,3,e))
          printf("已删除第3个元素,删除元素值为=%d\\n",e);
      else
          printf("位序i不合法,删除失败\\n");
      return 0;
  }

查找操作

按位查找
GetElem(L,i);        获取表中第i个位置的元素的值

#define MaxSize 10    //定义最大长度
  typedef struct{
      ElemType data[MaxSize];    //用静态的“数组”存放数据元素(静态分配)
      or
      ElemType *data;    //动态分配
      int length;    //顺序表的当前长度
  }SeqList;    //顺序表的类型定义(静态分配方式)
  ElemType GetElem(SeqList L, int i){
      return L.data[i-1];
  }

按值查找
LocateElem(L,e); 在表L中查找具有给定关键字的值

#define InitSize 10
  typedef struct{
      ElemType *data;
      int MaxSize;
      int length;
  }SeqList;
  //在顺序表L中查找第一个元素值等于e的元素,并返回其位序
  int LocateElem(SeqList L, ElemType e){
      for(int i=0; i<L.length; i++)
          if(L.data[i] == e;
              return i+1;
      return 0;
  }

单链表上基本操作的实现

头插法建立链表

LinkList List_HeadInsert(LinkList &L){  //逆向建立单链表 
    LNode *s;
    int x;
    L = (LinkList)malloc(sizeof(LNode));//创建头结点 
    L->nest = NULL;                      //初始为空链表 
    scanf("%d",&x);                       //输入结点的值 
    while(x!=9999){                     //输入9999表示结束 
        s=(LNode*)malloc(sizeof(LNode));//创建新结点 
        s->data = x;
        s->next = L->next;
        L->next = s;                 //将新结点插入表中,L为头指针 
        scanf("%d",&x);
    }
    return L;
  }

尾插法建立链表

LinkList List_TailInsert(LinkList &L){  //正向建立单链表 
    int x;                              //设ElemType为整型 
    L = (LinkList)malloc(sizeof(LNode));//建立头结点 
    LNode *s, *r=L;                     //r为表尾指针 
    scanf("%d",&x);                       //输入结点的值 
    while(x!=9999){                     //输入9999表示结束 
        s = (LNode*)malloc(sizeof(LNode));
        s->data = x;
        r->next = s;
        r=s;                            //r指向新的表尾结点 
        scanf("%d",&x);
    } 
    r->next->NULL;                        //尾结点指针置空 
    return L;
  }

 按序号查找结点

//按位查找,返回第i个元素(带头结点)
  LNode * GetElem(LinkList L, int i){
    if(i<0)
        return NULL;
    LNode *p;   //指针p指向当前扫描到的结点 
    int j=0;    //当前p指向的是第几个结点 
    p = L;      //L指向头结点,头结点是第0个结点(不存数据) 
    while(p!=NULL && j<i){   //循环找到第i个结点 
        p = p->next;
        j++;
    }
    return p;
  }

按值查找表结点

//按值查找,找到数据域==e的结点
  LNode *LocateElem(LinkList L, ElemType e){
    LNode *p = L->next;
    //从第1个结点开始查找数据域为e的结点
    while(p!=NULL && p->data!=e)
        p = p->next;
    return p;   //找到后返回该结点指针,否则返回NULL 
  }

插入结点操作

在第i个位置插入元素e(带头结点)

//在第i个位置插入元素e(带头结点) 
  bool ListInsert(LinkList &L,int i, ElemType e){
    if(i<1)
        return false;
    LNode *p;   //指针p指向当前扫描到的结点 
    int j=0;    //当前p指向的是第几个结点 
    p = L;      //L指向头结点,头结点是第0个结点(不存数据) 
    while(p!=NULL && j<i-1){ //循环找到第 i-1 个结点 
        p=p->next;
        j++;
    }
    if(p==NULL)     //i值不合法 
        return false;
    LNode *s = (LNode *)malloc(sizeof(LNode));
    s->data = e;
    s->next = p->next;
    p->next = s; //将结点s连到p之后 
    return true;    //插入成功 
  }

在第i个位置插入元素e(不带头结点)

//按位序插入(不带头结点)
  bool ListInsert (&L, int i, ElemType e){
    if(i<1)
        return false;
    if(i==1){   //插入第1个结点的操作与其他结点不同 
        LNode *s = (LNode *)malloc(sizeof(LNode));
        s->data = e;
        s->next = L;
        L = s;  //头指针指向新结点 
        return true;
    }
    LNode *p;   //指针p指向当前扫描到的结点 
    int j=1;    //当前p指向的是第几个结点 
    p = L;      //p指向第1个结点(注意:不是头结点) 
    while(p!=NULL && j<i-1){ //循环找到第i-1个结点 
        p = p->next;
        j++;
    }
    if(p==NULL)     //i值不合法 
        return false;
    LNode *s = (LNode *)malloc(sizeof(LNode));
    s->data = e;
    s->next = p->next;
    p->next = s;
    return true;    //插入成功 
  }

指定结点的前插、后插操作:

//前插操作:在p结点之前插入元素e
  bool InsertPriorNode(LNode *p,ElemType e){
    if(p==NULL)
        return false;
    LNode *s = (LNode *)malloc(sizeof(LNode));
    if(s==NULL)     //内存分配失败 
        return false;
    s->next = p->next;
    p->next = s;     //新结点s连到p之后 
    s->data = p->data;    //将p中元素复制到s中 
    p->data = e;     //p中元素覆盖为e 
    return true;
  }
//后插操作:在p结点之后插入元素e
  bool InsertNextNode(LNode *p, ElemType e){
    if(p==NULL)
        return false;
    LNode *s = (LNode *)malloc(sizeof(LNode));
    if (s==NULL)    //内存分配失败 
        return false;
    s->data = e; //用结点s保存数据元素e 
    s->next = p->next;
    p->next = s; //将结点s连到p之后 
    return true;
  }
//在第i个位置插入元素e(带头结点) 
  bool ListInsert(LinkList &L, int i, ElemTypee e){
    if(i<1)
        return false;
    LNode *p;    //指针p指向当前扫描到的结点
    int j=0;     //当前p指向的是第几个结点
    p = L;       //L指向头结点,头结点是第0个结点(不存数据)
    while(p!=NULL && j<i-1){    //循环找到第 i-1 个结点
        p = p->next;
        j++;
    }
    return InsertPriorNode(p,e);
    or
    return InsertNextNode(p,e);
  }

删除结点操作 

//删除指定结点p
  bool DeleteNode (LNode *p){
    if(p==NULL)
        return false;
    LNode *q = p->next;      //令q指向*p的后继结点 
    p->data = p->next->data;//和后继结点交换数据域 
    p->next = q->next;        //将*q结点从链中“断开” 
    free(q);                //释放后继结点的存储空间 
    return true;
  }

求表长操作

//求表的长度
  int Length(LinkList L){
    int len = 0;    //统计表长 
    LNode *p = L;
    while(p->next != NULL){
        p = p->next;
        len++;
    }
    return len;
  }

双链表

双链表的初始化

typedef struct DNode{           //定义双链表结点类型
    ElemType data;              //数据域 
    struct DNode *prior,*next;  //前驱和后继指针 
  }DNode, *DLinklist;               
  //初始化双链表(带头结点) 
  bool InitDLinklist(DLinklist &L){
    L = (DNode *)malloc(sizeof(DNode));
    if(L == NULL)
        return false;
    L->prior = NULL;
    L->next = NULL;
    return true; 
  } 
  void testDLinkList(){
    //初始化双链表
    DLinklist L;
    InitDLinkList(L);
    ...... 
  }

双链表的插入(后插)

//在p结点之后插入s结点
  bool InsertNextDNode (DNode *p, DNode *s){
    if(p==NULL || s==NULL)  //非法参数 
        return false;
    s->next = p->next;
    if(p-next != NULL)
        p->next->prior=s; //如果p结点后有后继节点 
    s->prior = p;
    p->next = s;
    return true; 
  }

双链表的删除(后删)

//删除p结点的后继结点
  bool DeleteNextDNode(DNode *p){
    if(p == NULL)   return false;
    DNode *q = p->next;      //找到p的后继结点q
    if(q == NULL)   return false;   //p没有后继 
    p->next = q->next;
    if(q->next != NULL)
        q->next->prior = p;
    free(q);        //释放结点空间 
    return true; 
  } 
  void DestoryList(DLinklist &L){
    //循环释放各个数据节点
    while (L->next != NULL)
        DeleteNextDNode(L);
    free(L);    //释放头结点 
    L = NULL;   //头指针指向NULL 
  }

双链表的遍历

//后向遍历
  while(p!=NULL){
    //对结点p做相应处理,如打印
    p = p->next; 
  } 
  //前向遍历
  while(p!=NULL){
    //对结点p做相应处理
    p = p->prior;
  }
  //前向遍历(跳过头结点) 
  while(p->prior!=NULL){
    //对结点p做相应处理
    p = p->prior;
  }

循环链表

循环单链表

typedef struct LNode{   //定义单链表结点类型 
    ElemType data;      //每个结点存放一个数据元素 
    struct LNode *next; //指针指向下一个结点 
  }LNode, *LinkList;
  //初始化一个循环单链表
  bool InitList(LinkList &L){
    L = (LNode *)malloc(sizeof(LNode)); //分配一个头结点 
    if(L==NULL)         //内存不足,分配失败 
        return false;
    L->next = L;     //头结点next指向头结点 
    return true;
  }
  //判断循环单链表是否为空
  bool Empty(LinkList L){
    if(L->next == L)
        return true;
    else
        return false;
  } 
  //判断结点p是否为循环单链表的表尾结点
  bool isTail(LinkList L, LNode *p){
    if(p->next == L)
        return true;
    else
        return false;
  }

循环双链表

typedef struct DNode{
    ElemType data;
    struct DNode *prior,*next;
  }DNode,*DLinklist;
  //初始化空的循环双链表
  bool InitDLinkList(DLinklist &L){
    L = (DNode *)malloc(sizeof(DNode)); //分配一个头结点 
    if(L==NULL)         //内存不足,分配失败 
        return false;
    L->prior = L;        //头结点的 prior 指向头结点 
    L->next = L;     //头结点的 next 指向头结点 
    return true;
  } 
  void testDLinkList(){
    //初始化循环双链表
    DLinklist L;
    InitDLinkList(L);
    ......
  }
  //判断循环双链表是否为空
  bool Empty(DLinklist L){
    if(L->next == L)
        return true;
    else
        return false;
  } 
  //判断结点p是否为循环双链表的表尾结点
  bool isTail(DLinklist L, DNode *p){
    if(p->next == L)
        return true;
    else
        return false;
  }

双链表的插入

//在p结点之后插入s结点
  bool InsertNextDNode(DNode *p, DNode *s){
    s->next = p->next;
    p->next->prior = s;
    s->prior = p;
    p->next = s;
  }

双链表的删除

//删除p的后继结点q
  p->next = q->next;
  q->next->prior = p;
  free(q);

静态链表

代码定义静态链表

#define MaxSize 10  //静态链表的最大长度 
  struct Node{      //静态链表结构类型的定义 
    ElemType data;  //存储数据元素  
    int next;       //下一个元素的数组下标 
  };
  typeof struct Node SLinkList [MaxSize];

第三章 栈、队列和数组

栈的顺序存储

栈的初始化

//初始化栈
  void InitStack(SqStack &S){
    S.top = -1;     //初始化栈顶指针 
  } 
  void testStack(){
    SqStack S;  //声明一个顺序栈(分配空间)
    InitStack(S);
    ...... 
  } 
  //判断栈空
  bool StackEmpty(SqStack S){
    if(S.top == -1)     //栈空
        return true;
    else
        return false;   //不空 
  }

进栈操作

//新元素入栈
  bool Push(SqStack &S,ElemType x){
    if(S.top == MaxSize-1)  //栈满,报错
        return false;
    S.top = S.top+1;        //指针先+1 
    S.data[S.top] = x;      //新元素入栈 
    return true; 
  }

出栈操作

//出栈操作
  bool Pop(SqStack &S,ElemType &x){
    if(S.top == -1)     //栈空,报错
        return false;
    x = S.data[S.top];  //栈顶元素先出栈 
    S.top = S.top-1;    //指针再-1 
    return true;
  }

读栈顶元素操作

//读栈顶元素操作 
  bool Pop(SqStack &S,ElemType &x){
    if(S.top == -1)     //栈空,报错
        return false;
    x = S.data[S.top];  //x记录栈顶元素   
    return true;
  }

共享栈

//共享栈
  #define MaxSize 10            //定义栈中元素的最大个数 
  typedef struct{
    ElemType data[MaxSize]; //静态数组存放栈中元素 
    int top0;               //0号栈栈顶指针 
    int top1;               //1号栈栈顶指针
  }ShStack; 
  //初始化栈
  void InitStack(ShStack &S){
    S.top0 = -1;
    S.top1 = MaxSize;
  }

 栈的链式存储

链栈的定义

typedef struct Linknode{
    ElemType data;          //数据域 
    struct Linknode *next;  //指针域 
  }*LiStack;                    //栈类型定义

链栈的进栈、出栈操作

对应头插法建立单链表(进栈)、单链表的删除操作(出栈)

队列的顺序实现

队列的初始化

#define MaxSize 10  //定义队列中元素的最大个数
  typedef struct{
    ElemType data[MaxSize]; //用静态数组存放队列元素
    int front,rear;         //队头指针和队尾指针 
  }SqQueue;
  //初始化队列
  void InitQueue(SqQueue &Q){
    //初始时 队头、队尾指针指向0
    Q.rear = Q.front = 0; 
  } 
  void testQueue(){
    //声明一个队列(顺序存储)
    SqQueue Q;
    InitQueue(Q);
    ...... 
  }
  //判断队列是否为空
  bool QueueEmpty(SqQueue Q) {
    if(Q.rear == Q.front)   //队空条件
        return true;
    else 
        return false; 
  }

入队操作

判断队满:rear == MaxSize?
当队尾等于最大长度时有可能是队满,也有可能存在假溢出(可以>使用循环队列解决这个问题)

//入队操作
  bool EnQueue(SqQueue &Q,ElemType x){
    if(队列已满)
        return false;   //队满则报错
    Q.data[Q.rear] = x;
    Q.rear = Q.rear+1;
    return true; 
  }

循环队列

队列已满的条件:队尾指针的再下一个位置就是队头
即:(Q.rear+1)%MaxSize == Q.front

//判断队列是否为空
  bool QueueEmpty(SqQueue Q){
    if(Q.rear == Q.front)   //队空条件
        return true;
    else
        return false; 
  } 
  //入队
  bool EnQueue(SqQueue &Q,ElemType x){
    if((Q.rear+1)%MaxSize == Q.front)
        return false;           //队满则报错
    Q.data[Q.rear] = x;         //新元素插入队尾 
    Q.rear = (Q.rear+1)%MaxSize; //队尾指针+1取模
    return true; 
  } 
  //出队(删除一个队头元素,并用x返回) 
  bool DeQueue(SqQueue &Q,ElemType &x){
    if(Q.rear == Q.front)
        return false;       //队空则报错 
    x = Q.data[Q.front];
    Q.front = (Q.front+1)%MaxSize;
    return true; 
  } 
  //获得队头元素的值,用x返回
  bool GetHead(SqQueue Q,ElemType &x){
    if(Q.rear == Q.front)
        return false;   //队空则报错
    x = Q.data[Q.front]
    return true; 
  }

判断队列已满/已空
方案一:牺牲一个位置存放队尾指针
方案二:定义size变量,表示队列当前长度
方案三:定义tag变量,表示最近进行的是插入or删除

队列的链式实现

typedef struct LinkNode {   //链式队列结点
    ElemType data;
    struct LinkNode *next; 
  }LinkNode;
  typedef struct{               //链式队列 
    LinkNode *fron,*rear;   //队列的队头和队尾指针 
  }LinkQueue;

队列的初始化

//初始化队列(带头结点)
  void InitQueue (LinkQueue &Q){
    //初始时 front、rear 都指向头结点
    Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
    Q.front->next = NULL;
  } 
  //判断队列是否为空(带头结点)
  bool IsEmpty(LinkQueue Q){
    if(Q.front == Q.rear)
        return true;
    else
        return false;
  } 
  ----------------------------------------
  //初始化队列(不带头结点)
  void InitQueue(LinkQueue &Q){
    //初始时 front、rear 都指向NULL
    Q.front= NULL;
    Q.rear = NULL; 
  } 
  //判断队列是否为空(不带头结点)
  bool IsEmpty(LinkQueue Q){
    if(Q.front == NULL)
        return true;
    else
        return false;
  } 
  void testLinkQueue(){
    LinkQueue Q;    //声明一个队列
    InitQueue(Q);   //初始化队列
    ...... 
  }

入队操作

//新元素入队(带头结点)
  void EnQueue(LinkQueue &Q,ElemType x){
    LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
    s->data = x;
    s->next = NULL;
    Q.rear->next = s;    //新结点插入到rear之后 
    Q.rear = s;         //修改表尾指针 
  } 
  ------------------------------------------------------- 
  //新元素入队(不带头结点)
  void EnQueue(LinkQueue &Q,ElemType x){
    LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
    s->data = x;
    s->next = NULL;
    if(Q.front == NULL){    //在空队列中插入第一个元素 
        Q.front= s;         //修改队头队尾指针 
        Q.reat= s;
    }else{
        Q.rear->next = s;    //新结点插入到 rear 之后 
        Q.rear = s;         //修改rear指针 
    }
  }

出队操作

//队头元素出队(带头结点)
  bool DeQueue(LinkQueue  &Q,ElemType &x){
    if(Q.front == Q.rear)
        return false;   //空队
    LinkNode *p = Q.front->next;//p指针指向要删除的结点(队头元素出队)
    x = p->data; //用变量x返回队头元素
    Q.front->next = p->next;  //修改头结点的next指针
    if(Q.rear == p)             //此次是最后一个结点出队 
        Q.rear = Q.front;       //修改 rear 指针 
    free(p);                    //释放结点空间 
    return true;
  }
//队头元素出队(不带头结点)
  bool DeQueue(LinkQueue &Q,ElemType &x){
    if(Q.front == NULL)
        return false;   //空队
    LinkNode *p = Q.front; //p指向此次出队的结点
    x = p->data;        //用变量x返回队头元素
    Q.front = p->next;      //修改front指针
    if(Q.rear == p){       //此次是最后一个结点出队 
        Q.front = NULL;    //front 指向 NULL 
        Q.rear = NULL;     //rear 指向 NULL 
    } 
    free(p);
    return true; 
  }

栈在括号匹配中的应用

算法实现

bool bracketCheck(char str[],int length){
    SqStack S;
    InitStack(S);   //初始化一个栈
    for(int i=0; i<length; i++){
        if(str[i] == '(' || str[i] == '[' || str[i] == '{')
            Push(S,str[i]);     //扫描到左括号,压入栈 
    }else{
        if(StackEmpty(S))       //扫描到右括号,且当前栈空 
            return false;       //扫描失败
        char topElem;
        Pop(S,topElem);         //栈顶元素出栈 
        if(str[i] == ')' && topElem != '(')
            return false;
        if(str[i] == ']' && topElem != '[')
            return false;
        if(str[i] == '}' && topElem != '{')
            return false;
    } 
    return StackEmpty(S);       //检索完全部括号后,栈空说明匹配成功 
  }

匹配失败情况:①左括号单身 ②右括号单身 ③左右括号不匹配

第四章 串

串的存储结构

顺序存储

#define MAXLEN 255      //预定义最大串长为255
  //静态数组实现(定长顺序存储)
  typedef struct{
    char ch[MAXLEN];    //每个分量存储一个字符 
    int length;         //串的实际长度 
  }SString; 
  //动态数组实现(堆分配存储) 
  typedef struct{
    char *ch;       //按串长分配存储区,ch指向串的基地址    
    int length;     //串的长度 
  }HString; 
  HString S;
  S.ch = (char *) malloc(MAXLEN * sizeof(char));
  S.length = 0;

链式存储

typedef struct StringNode{
    char ch;    //每个结点存1个字符
    struct StringNode * next; 
  }StringNode, * String;
  typedef struct StringNode{
    char ch[4]; //每个结点存4个字符
    struct StringNode * next; 
  }StringNode, * String;

基本操作(求子串、串的比较、定位操作)

//求子串(用Sub返回串S的第pos个字符起长度为len的子串) 
  bool SubString(SString &Sub, SString s, int pos,int len){
    //子串范围越界
    if(pos+len-1 > S.length)
        return false;
    for(int i=pos; i<pos+len; i++)
        Sub.ch[i-pos+1] = S.ch[i];
    Sub.length = len;
    return true;
  } 
  //串的比较(若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0) 
  int StrCompare(SString S, SString T){
    for(int i=1; i<=S.length && i<=T.length; i++){
        if(S.ch[i] != T.ch[i])
            return S.ch[i]-T.ch[i];
    }
    //扫描过的所有字符都相同,则长度长的串要大
    return S.length - T.length; 
  } 
  //求串在主串中的位置(若S中存在与串T相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0)
  int Index(SString S, SString T){
    int i=1, n=StrLength(S), m=StrLength(L);
    SString sub;    //用于暂存子串
    while(i<=n-m+1){
        SubString(Sub,s,i,m);
        if(StrCompare(sub,T)!=0)  ++i;
        else return i;  //返回子串在主串中的位置 
    } 
    return 0;   //S中不存在与T相等的子串 
  }

匹配算法

 朴素模式匹配算法

最坏时间复杂度:O(nm)

//朴素模式匹配算法
  int Index(SSring S,SString T){
    int i=1,j=1;
    while(i<=s.length && j<=T.length){
        if(S.ch[i] == S.ch[j]){
            ++i; ++j;   //继续比较后续字符 
        }
        else{
            i=i-j+2;    //i=(i-(j-1))+1 
            j=1;    //指针后退重新开始匹配 
        } 
    }
    if(j>T.length)
        return i-T.length;
    else
        return 0; 
  }

i=i-j+2 的解释:
当i=j=6,模式串与主串不匹配时,i需要回到起始元素的下一个>位置2,j回到1才能进行下一次匹配,即 i-(j-1),i回到1位置>后再加一:i = i -( j-1)+1 = i-j+2

KMP匹配算法

//KMP匹配算法
  int Index_KMP(SSring S,SString T,int next[]){
    int i=1,j=1;
    while(i<=s.length && j<=T.length){
        if(j==0 || S.ch[i] == S.ch[j]){
            ++i; ++j;   //继续比较后续字符 
        }
        else
            j = next[i];    //模式串向后移动 
    }
    if(j>T.length)
        return i-T.length;  //匹配成功 
    else
        return 0; 
  }

第五章 树与二叉树

二叉树的存储结构

顺序存储

#define MaxSize 100
  struct TreeNode{
    ElemType value;     //结点中的数据结构
    bool isEmpty;       //结点是否为空 
  }; 
  TreeNode t[MaxSize];
  for(int i=0; i<MaxSize; i++){
    t[i].isEmpty = true;
  }

链式存储

//二叉树的结点(链式存储)
  struct ElemType{
    int value;
  };
  typedef struct BiTNode{
    ElemType data;      //数据域
    struct BiTNode *lchild,*rchild; //左、右孩子指针 
      (sruct BiTNode *parent;)  //父结点指针 
  }BiTNode,*BiTNode; 
  //定义一棵空树
  BiTree root = NULL;
  //插入根节点
  root = (BiTree) malloc(sizeof(BiTNode));
  root->data = {1};
  root->lchild = NULL;
  root->rchild = NULL;
  //插入新结点
  BiTree *p = (BiTNode *) malloc(sizeof(BiTNode));
  p->data = {2};
  p->lchild = NULL;
  p->rchild = NULL;
  root->lchild = p;  //作为根节点的左孩子

二叉树的遍历和线索二叉树

二叉树的遍历

//先序遍历
  void PreOrder(BiTree T){
    if(T != NULL){
        visit(T);           //访问根节点
        PreOrder(T->lchild);//递归遍历左子树 
        PreOrder(T->rchild);//递归遍历右子树 
    }
  } 
  //中序遍历
  void InOrder(BiTree T) {
    if(T != NULL){
        InOrder(T->lchild);//递归遍历左子树 
        visit(T);           //访问根节点
        InOrder(T->rchild);//递归遍历右子树 
    }
  }
  //后序遍历 
  void PostOrder(BiTree T){
    if(T != NULL){
        PostOrder(T->lchild);//递归遍历左子树 
        PostOrder(T->rchild);//递归遍历右子树
        visit(T);           //访问根节点
    }
  }

例:求树的深度(应用)

int treeDepth(BiTree T){
    if(T == NULL){
        return 0;
    }else{
        int l = treeDepth(T->lchild);
        int r = treeDepth(T->rchild);
        //树的深度 = Max(左子树深度,右子树深度)+ 1
        return l>r? l+1:r+1; 
    }
  }

层序遍历

//层序遍历
  void LevelOrder(BiTree T){
    LinkQueue Q;    
    InitQueue(Q);           //初始化辅助队列 
    BiTree p;
    EnQueue(Q,T);           //将根节点入队
    while(!IsEmpty(Q)){     //队列不空则循环 
        DeQueue(Q,p);       //对头结点出队
        visit(p);           //访问出队结点
        if(p->lchild!=NULL)
            EnQueue(Q,p->lchild);    //左孩子入队 
        if(p->rchild!=NULL)
            EnQueue(Q,p->rchild);    //右孩子入队 
    } 
  } 
  typedef struct BiTNode{
    ElemType data;  
    struct BiTNode *lchild,*rchild; 
  }BiTNode,*BiTNode; 
  //链式队列结点
  typedef struct LinkNode{
    BiTNode * data;
    struct LinkNode *next;
  }LinkNode;
  typedef struct{
    LinkNode *front,*rear;  //队头队尾 
  }LinkQueue;

线索二叉树

//线索二叉树结点
  typedef struct ThreadNode{
    ElemType data;
    struct ThreaDNode *lchild,*rchild;
    int ltag,rtag;  //左、右线索标志 
    //ltag == 1,表示lchild指向前驱;ltag == 0,表示lchild指向左孩子
    //rtag == 1,表示rchild指向前驱;rtag == 0,表示rchild指向右孩子
  }ThreadNode,*ThreadTree;

土办法找到中序前驱

//土办法找中序前驱
  void findPre(BiTree){
    if(T!=NULL){
        findPre(T->lchild);
        visit(T);
        findPre(T->rchild);
    }
  } 
  //访问结点p
  void visit(BiTNode *q){
    if(p==q)            //当前访问结点刚好是结点p 
        final = pre;    //找到p的前驱
    else
        pre = q; 
  } 
  //辅助全局变量,便于查找p的前驱
  BiTNode *p;               //p指向目标结点 
  BiTNode * pre = NULL; //指向当前访问结点的前驱 
  BiTNode * final = NULL; //用于记录最终结果
中序线索化
//中序线索化
  //全局变量pre,指向当前访问结点的前驱
  ThreadNode *pre = NULL;
  //中序线索化二叉树T
  void CreateInThread(ThreadTree T){
    pre = NULL;             //初始化pre为NULL 
    if(T!=NULL){            //非空二叉树才能线索化 
        InThread(T);        //中序线索化二叉树 
        if(pre->rchild == NULL)
            pre->rtag = 1;   //处理遍历的最后一个结点 
    }
  } 
  //线索二叉树结点
  typedef struct ThreadNode{
    ElemType data;
    struct ThreadNode *lchild,*rchild;
    int ltag,rtag;
  }ThreadNode,*ThreadTree;
  //中序遍历二叉树,一边遍历一遍线索化
  void InThread(ThreadTree T){
    if(T!=NULL){
        InThread(T->lchild);
        visit(T);
        InThread(T->rchild);
    }
  } 
  void visit(ThreadNode *q){
    if(q->lchild == NULL){   //左子树为空,建立前驱线索 
        q->lchild = pre;
        q->ltag =  1;
    }
    if(pre!=NULL && q->rchild == NULL){
        pre->rchild = q; //建立前驱结点的后驱线索 
        pre->rtag = 1;
    } 
    pre = q;
  }
先序线索化
//先序线索化
  //全局变量pre,指向当前访问结点的前驱
  ThreadNode *pre = NULL;
  //先序线索化二叉树T
  void CreatePreThread(ThreadTree T){
    pre = NULL;                 //pre初始化为NULL
    if(T!=NULL){                //非空二叉树才能线索化 
        PreThread(T);           //先序线索化二叉树 
        if(pre->rchild == NULL)
            pre->rchild = 1; //处理遍历的最后一个结点 
    } 
  }
  //先遍历二叉树,一边遍历一遍线索化
  void PreThread(ThreadTree T){
    if(T!=NULL){
        visit(T);           //先处理根节点 
        if(T->ltag == 0) //lchild不是前驱线索
            PreThread(T->lchild);
        PreThread(T->rchild); 
    }
  } 
  void visit(ThreadNode *q){
    if(q->lchild == NULL){   //左子树为空,建立前驱线索 
        q->lchild = pre;
        q->ltag = 1;
    }
    if(pre!=0 && q->rchild == NULL){
        pre->rchild = q; //建立前驱结点的后继线索 
        pre->rtag = 1;
    }
    pre = q;
  }
后序线索化
//后序线索化
  //全局变量pre,指向当前访问结点的前驱
  ThreadNote *pre = NULL;
  //后序线索化二叉树T
  void CreatPostThread(ThreadTree T){
    pre = NULL;             //pre初始为NULL 
    if(T!=NULL){            //非空二叉树才能线索化 
        PostThread(T);      //后序线索化二叉树 
        if(pre->rchild == NULL)
            pre->rtag = 1;   //处理遍历的最后一个结点 
    } 
  } 
  //后序遍历二叉树,一边遍历一边线索化 
  void postThread(ThreadTree T){
    if(T!==NULL){
        PostThread(T->lchild);   //后序遍历左子树
        PostThread(T->rchild);   //后序遍历右子树
        visit(T);               //访问根节点 
    } 
  } 
  void visit(ThreadNode *q){
    if(q->lchild == NULL){   //左子树为空,建立前驱线索 
        q->lchild = pre;
        q->ltag = 1;
    }
    if(pre!=NULL && q->rchild == NULL){
        pre->rchild = q; //建立前驱结点的后继线索
        pre->rtag = 1; 
    }
    pre = q;
  }

  线索二叉树找前驱/后继

中序线索二叉树找中序后继
//中序线索二叉树找中序后继
  //找到以P为根的子树中,第一个被中序遍历的结点
  ThreadNode *Firstnode(ThreadNode *p){
    //循环找到最左下结点(不一定是叶结点)
    while(p->ltag == 0)
        p=p->lchild;
    return p; 
  } 
  //在中序线索二叉树中找到结点p的后继结点
  ThreadNode *Nextnode(ThreadNode *p){
    //右子树中最左下结点
    if(p->rtag == 0)
        return Firstnode(p->rchild);
    else 
        return p->rchild;    //rtag==1直接返回后继线索 
  } 
  //对中序线索二叉树进行中序遍历(利用线索实现的非递归算法)
  void Inorder(ThreadNode *T){
    for(ThreadNode *p=Firstnode(T); p!=NULL; p=Nextnode(p))
        visit(p);
  }
中序线索二叉树找中序前驱 
//中序线索二叉树找中序前驱
  //找到以P为根的子树中,最后一个被中序遍历的结点
  ThreadNode *Lastnode(ThreadNode *p){
    //循环找到最右下的结点(不一定是叶结点)
    while(p->rtag == 0)
        p=p->rchild;
    return p; 
  } 
  //在中序线索二叉树中找到结点p的前驱结点
  ThreadNode *Prenode(ThreadNode *p){
    //左子树中最右下结点
    if(p->ltag == 0)
        return Lastnode(p->lchild);
    else
        return p->lchild;    //ltag==1直接返回前驱线索 
  } 
  //对中序线索二叉树进行逆向中序遍历
  void RevInorder(ThreadNode *T){
    for(ThreadNode *p=Lastnode(t); p!=NULL; p=Prenode(p));
    visit(p);
  }

树和森林

树的存储结构

双亲表示法(顺序存储)
//双亲表示法(顺序存储)
  #define MAX_TREE_SIZE 100     //树中最多结点数
  typedef struct{                   //树中的结点定义
    ElemType data;              //数据元素 
    int parent;                 //双亲位置域 
  }PTNode;
  typedef struct{                   //树的类型定义 
    PTNode nodes[MAX_TREE_SIZE];//双亲表示 
    int n;                      //结点数 
  }PTree;
孩子表示法(顺序+链式存储)
//孩子表示法
  struct CTNode{
    int child;  //孩子结点在数组中的位置 
    struct CTNode *next;    //下一个孩子 
  }; 
  typedef struct{
    ElemType data;
    struct CTNode *firstChild;  //第一个孩子 
  }CTBox;
  typedef struct{
    CTBox nodes[mAX_TREE_SIZE];
    int n, r;   //结点数和根的位置 
  }CTree;
孩子兄弟表示法(链式存储)
//孩子兄弟表示法
  typedef struct CSNode{
    ElemType data;      //数据域 
    struct CSNode *firstchild,*nextsibling; //第一个孩子和右兄弟指针 
  }CSNode,*CSTree;

树的遍历

先根遍历
//树的先根遍历
  void PreOrder(TreeNode *R){
    if(R!=NULL){
        visit(R);   //访问根节点
        while(R还有下一个子树T)
            PreOrder(T);    //先根遍历下一个子树 
    }
  }
后根遍历
//树的后根遍历
  void PostOrder(TreeNode *R){
    if(R!=NULL){
        while(R还有下一个子树T)
            PostOrder(T);   //后根遍历下一棵子树 
        visit(R);   //访问根节点 
    }
  }

  并查集

基本操作
//并查集的基本操作
  #define SIZE 13
  int UFSets[SIZE]; //集合元素数组
  //初始化并查集
  void Initial(int S[]){
    for(int i=0; i<SIZE; i++)
        S[i] = -1;
  } 
  //Find “查”操作,找x所属集合(返回x所属根节点)
  int Find(int S[],int x){
    while(S[x]>=0)       //循环寻找x的根
        x = S[x];
    return x;           //根的S[]小于0 
  } 
  //Union “并”操作,将两个集合合并为一个 
  void Union(int S[],int Root1,int Root2){
    //要求Root1与Root2是不同的集合
    if(Root1 == Root2)  return;
    //将根Root2连接到另一根Root1下面
    S[Root2] = Root1; 
  }
Union的优化
//Union “并”操作,小树合并到大树
  void Union(int S[],int Root1,int Root2){
    if(Root1 == Root2)  return;
    if(S[Root2]>S[Root1]){       //Root2结点数更少 
        S[Root1] += S[Root2];   //累加节点总数 
        S[Root2] = Root1;       //小树合并到大树 
    }else{
        S[Root2] += S[Root1];   //累加结点总数 
        S[Root1] = Root2        //小树合并到大树 
    }
  }
Find的优化
//Find “查”操作,先找到根节点,再进行“压缩路径” 
  int Find(int S[],int x){
    int root = x;
    while(S[root]>0) root = S[root]; //循环找到根
    while(x != NULL){   //压缩路径 
        int t = S[x];   //t指向x的父节点 
        S[x] = root;    //x直接挂到根节点下 
        x = t;
    } 
    return root;        //返回根结点编号 
  }

第六章 图

图的存储

邻接矩阵法

//邻接矩阵法
  #define MaxVertexNum 100      //顶点数目的最大值 
  typedef struct{
    char Ver[MaxVertexNum];                 //顶点表 
    int Edge[MaxVertexNum][MaxVertexNum];   //邻接矩阵、边表
    int vexnum,arcnum;                      //图的当前顶点数和边数/弧数 
  }MGraph; 
  //邻接矩阵法存储带权图  
  #define MaxVertexNum 100      //顶点数目的最大值 
  #define INFINITY 最大的int值  //宏定义常量“无穷” 
  typedef char VertexType;      //顶点的数据类型 
  typedef int EdgeType;         //带权图中边上权值的数据类型 
  typedef struct{
    VertexType Vex[MaxVertexNum];               //顶点 
    EdgeType Edge[MaxVertexNum][MaxVertexNum];  //边的权 
    int vexnum,arcnum;                          //图的当前顶点数和弧数 
  }MGraph;

邻接表法

//用邻接表存储的图
  typedef struct{
    AdjList vertices;
    int vexnum,arcnum;
  }ALGRaph; 
  //“边/弧” 
  typedef struct ArcNode{
    int adjvex;             //边/弧指向哪个结点 
    struct ArcNode *next;   //指向下一条弧的指针 
    //InfoType info;        //边权值 
  }ArcNode; 
  //顶点
  typedef struct VNode{
    VertexType data;    //顶点信息 
    ArcNode *first;     //第一条边/弧 
  }VNode,AdjList[MaxvertexNum];

图的遍历

广度优先遍历BFS

//广度优先遍历 
  bool visited[MAX_VERTEX_NUM]; //访问标记数组 
  void BFSTraverse(Graph G){        //对图G进行广度优先遍历   
    for(i=0; i<G.vexnum; ++i)     
        visited[i] = FALSE;     //访问标记数组初始化 
    InitQueue(Q);               //初始化辅助队列Q 
    for(i=0; i<G.vexnum; ++i)    //从0号顶点开始遍历  
        if(!visited[i])         //对每个连通分量调用一次BFS 
            BFS(G,i);           //vi未访问过,从vi开始BFS 
  } 
  void BFS(Graph G,int v){      //从顶点v出发,广度优先遍历图G 
    visit(v);                   //访问初始顶点v 
    visited[i] = TRUE;          //对v做已访问标记 
    Enqueue(Q,v);               //顶点v入队列Q 
    while(!isEmpty(Q)){
        DeQueue(Q,v);           //顶点v出队列 
        for(w=FirstNeighbor(G,v); w>=0; w=NextNeighbor(G,v,w))
            //检测v所有邻接点
            if(!visited[w]){    //w为v的尚未访问的邻接顶点 
                visit(w);       //访问顶点w 
                visited[w]=TRUE;//对w做已访问标记 
                EnQueue(Q,w);   //顶点w入队列 
            }//if
    }//while
  }

深度优先遍历DFS

//深度优先遍历
  bool visited[MAX_VERTEX_NUM]; //访问标记数组
  void DFSTraverse(Graph G){        //对图G进行深度优先遍历 
    for(v=0; v<G.vexnum; ++v)
        visited[v] = FALSE;     //初始化已访问标记数据 
    for(v=0; v<G.vexnum; ++v)    //从v = 0开始遍历 
        if(!visited[w])
            DFS(G,v);
  } 
  void DFS(Graph G,int v){  //从顶点v出发,深度优先遍历G 
    visit(v);               //访问顶点v 
    visited[v] = TRUE;      //设已访问标记 
    for(w=FirstNeighbor(G,v); w>=0; w=NextNeighor(G,v,w))
        if(!visited[w]){    //w为u的尚未访问的邻接顶点 
            DFS(G,w);
        }   //if
  }

图的应用

最短路径问题

BFS算法
//求顶点u到其他顶点的最短路径
  void BFS_MIN_Distance(Graph G,int u){
    //d[i]表示u到i结点最短路径 
    for(i=0; i<G.vexnum; ++i){
        d[i] = ∞;       //初始化路径长度 
        path[i] = -1;   //最短路径从哪个顶点过来 
    } 
    d[u] = 0;
    visited[u] = TRUE;
    EnQueue(Q,u);
    while(!isEmpty(Q)){
        while(!isEmpty(Q)){             //BFS算法主过程 
            DeQueue(Q,u);               //队头元素u出队 
            for(w=FirstNeighbor(G,u); w>=0; w=NextNeighbor(G,u,w))
                if(!visited[w]){        //w为u的尚未访问的邻接顶点 
                    d[w] = d[u]+1;      //路径长度加1 
                    path[w] = u;        //最短路径应从u到w 
                    visited[w] = TRUE;  //设已访问标记 
                    EnQueue(Q,w);       //顶点w入队 
                }//if
        }//while
    }
  }
Dijkstra算法

初始:若从v0开始,令final[0]=true; dist[0]=0; path[0]=-1。
其余顶点final[k]=false; dist[k]=arcs[0][k]; path[k]=(arc[0][k]== ∞)? -1:0
n-1轮处理:循环遍历所有的顶点,找到还没确定最短路径,且dist最小的顶点vi,令final[i]=true。并检查所有邻接自vi的顶点,对于邻接自vi的顶点vj,若final[j]=false 且 dist[i]+arcs[i][j]<dist[j],则令dist[j]=dist[i]+arcs[i][j];path[j]=i(注:arcs[i][j]表示vi到vj的弧的权值)

Floyd算法
//Floyd核心代码
  //......核心代码,根据图的信息初始化矩阵A和path
  for(int k=0; k<n; k++){            //考虑以 vk 为中转点 
    for(int i=0; i<n; i++){      //遍历整个矩阵,i为行号,j为列号 
        for(int j=0; j<n; j++){
            if(A[i][j] > A[i][k] + A[k][j]){ //以 vk 为中转点的路径更短 
                A[i][j] = A[i][k] + A[k][j];    //更新最短路径长度 
                path[i][j] = k;                 //中转点 
            }
        }
    }
  }

拓补排序

//拓补排序
  #define MaxVertexNum 100  //图中顶点数目的最大值
  typedef struct ArcNode{       //边表结点 
    int adjvex;         //该弧所指向的顶点的位置 
    struce ArcNode *nextarc;//指向下一条弧的指针 
    //InfoType info;        //网的边权值 
  }ArcNode;
  typedef struct VNode{     //顶点表结点 
    VertexType data;        //顶点信息 
    ArcNode * firstare;     //指向第一条依附该顶点的弧的指针 
  }VNode,AdjList[MaxvertexNum];
  typedef struct{
    AdjList vertices;       //邻接表 
    int vexnm,arcnum;       //图的顶点数和弧数 
  }Graph;                   //Graph是以邻接表存储的图类型 
  bool TopologicalSort(Graph G){
    InitStack(S);
    for(int i=0 ;i<G.vexnum; i++)
        if(indegree[i] == 0)
            Push(S,i);
    int count=0;
    while(!IsEmpty(S)){
        Pop(S,i);
        print[count++]=i;
        for(P=G.vertices[i].firstarc; p; p->nextarc){
        //将所有i指向的顶点的入度减1,并且讲入度减为0的顶点压入栈S
        v=p->adjvex;
        if(!(--indegree[v])) 
            Push(S,v);  
        }
    }//while
  if(count<G.vexnum)
    return false;
  else
    return true;
  }
//逆拓补排序的实现(DFS算法)
  void DFSTraverse(Graph G){    //对图G进行深度优先遍历 
    for(v=0; v<G.vexnm; v++)
        visited[v]=FALSE;   //初始化已访问标记数据 
    for(v=0; v<G.vexnm; v++)//从v=0开始遍历 
        if(!visited[v])
            DFS(G,v);
  } 
  void DFS(Graph G,int v){  //从顶点v出发,深度优先遍历图G 
    visited[v]=TRUE;        //设已访问标记 
    for(w=FirstNeighbor(G,v); w>=0; w=NextNeighbor(G,v,w))
        if(!visited[w]){    //w为u的尚未访问的邻接顶点 
            DFS(G,w);
        }//if
    print(v);               //输出顶点 
  }

第七章 查找

基本查找操作

顺序查找

typedef struct{     //查找表的数据结构(顺序表) 
    ElemType *elem; //动态数组基址 
    int TableLen;   //表的长度 
  }SSTable;
  //顺序查找 
  int Search_Seq(SSTable ST,ElemType key){
    int i;
    for(i=0; i<ST.TableLen && ST.elem[i] != key; ++i);
    //查找成功,则返回元素下标;查找失败,则返回-1
    return i==ST.TableLen? -1:i; 
  } 
  //顺序查找(哨兵)
  int Search_Seq(SSTable ST,ElemType key){
    (ST.elem[0] = key;) //哨兵 
    int i;
    for(i=ST.TableLen; ST.elem[i] != key; --i); //引入哨兵时 
    //查找成功,则返回元素下标;查找失败,则返回0 
    return i; 
  }

折半查找

//折半查找
  int Binary_Search(SSTable L, ElemType key){
    int low = 0, high = L.TableLen-1, mid;
    while(low <= high){
        mid = (low + high)/2;       //取中间位置 
        if(L.elem[mid] == key)
            return mid;             //查找成功则返回所在位置 
        else if(L.elem[mid] > key)
            high = mid - 1;         //从前半部分继续查找 
        else
            low = mid + 1;          //从后半部分继续查找 
    }
    return -1;                      //查找失败,返回-1 
  }

分块查找

//索引表
  typedef struct{
    ElemType maxValue;
    int low,high;
  }Index;
  //顺序表实际存储元素
  ElemType List[100];

树型查找

二叉排序树(BST)

二叉树的查找
//二叉排序树结点
  typedef struct BSTNode{
    int key;
    struct BSTNode *lchild,*rchild;
  }BSTNode,*BSTree; 
  //在二叉排序树中查找值为key的结点
  BSTNode *BST_Search(BSTree T,int key){
    while(T!=NULL && key!=T->key){   //若树空或等于根结点值,则结束循环 
        if(key<T->key)
            T=T->lchild; //小于,则在左子树上查找 
        else
            T=T->rchild; //大于,则在右子树上查找 
    }
    return T;
  }
//在二叉排序树中查找值为key的结点(递归实现)
  BSTNode *BSTSearch(BSTree T, int key){
    if(T == NULL)
        return NULL;    //查找失败
    if(key == T->key)
        return T;       //查找成功
    else if(key < T->key)
        return BSTSearch(T->lchild,key); //在左子树中找
    else
        return BSTSearch(T->rchild,key); //在右子树中找 
  }
二叉树的插入
//在二叉排序树插入关键字为k的新结点(递归实现)
  int BST_Insert(BSTree &T, int k){
    if(T==NULL){            //原树为空,新插入结点为根结点 
        T=(BSTree)malloc(sizeof(BSTNode));
        T->key = k;
        T->lchild = T->rchild = NULL;
        return 1;           //返回插入成功 
    }
    else if(k == T->key) //树中存在相同关键字的结点,插入失败 
        return 0; 
    else if(k<T->key)     //插入到T的左子树 
        return BST_Insert(T->lchild,k);
    else                    //插入到T的右子树 
        return BST_Insert(T->rchild,k); 
  }
二叉树的构造
//按照 str[] 中的关键字序列建立二叉排序树
  void Creat_BST(BSTree &T,int str[],int n){
    T=NULL;         //初始时T为空树 
    int i=0;
    while(i<n){      //依次将每个关键字插入到二叉排序树中 
        BST_Insert(T,str[i]);
        i++;
    }
  }

第八章 排序

插入排序

直接插入排序

//直接插入排序
  void InsertSort(int A[], int n){
    int i,j,temp;
    for(i=1; i<n; i++)           //将各元素插入已排好序的序列中 
        if(A[i]<A[i-1]){     //若A[i]关键字小于前驱 
            temp = A[i];        //用temp暂存A[i] 
            for(j=i-1; j>=0&&A[j]>temp; --j)  //检查所有前面已排好序的元素 
                A[j+1] = A[j];  //所有大于temp的元素都向后挪位 
            A[j+1] = temp;      //复制到插入位置 
        }
  } 
  //直接插入排序(带哨兵)
  void InsertSort(int A[], int n){
    int i,j;
    for(i=2; i<=n; i++)          //依次将A[2]~A[n]插入到前面已排序序列 
        if(A[i]<A[i-1]){     //若A[i]关键字小于前驱,将A[i]插入有序表 
            A[0] = A[i];        //复制为哨兵,A[0]不存元素 
            for(j=i-1; A[0]<A[j]; --j)   //向后往前查找待插入位置 
                A[j+1] = A[j];  //向后挪位 
            A[j+1] = A[0];      //复制到插入位置 
        }
  }

折半插入排序

//折半插入排序
  void InsertSort(int A[], int n){
    int j,i,low,high,mid;
    for(i=2; i<=n; i++){         //依次将A[2]~A[n]插入前面的已排序序列 
        A[0]=A[i];                  //将A[i]暂存到A[0] 
        low = 1; high = i-1;        //设置折半查找的范围 
        while(low<=high){            //折半查找(默认递增有序) 
            mid=(low+high)/2;       //取中间点 
            if(A[mid]>A[0])  high = mid-1;//查找左半子表 
            else low = mid+1;       //查找右半子表 
        }
        for(j=i-1; j>=high+1; --j)
            A[j+1] = A[j];          //统一后移元素,空出插入位置 
        A[high+1] = A[0];           //插入操作 
    }
  }

希尔排序

//希尔排序
  void ShellSort(int A[],int n){
    int d,i,j;
    //A[0]只是暂存单元,不是哨兵,当j<=0时,插入位置已到
    for(d=n/2; d>=1; d=d/2)  //步长变化
        for(i=d+1; i<=n; ++i)
            if(A[i]<A[i-d]){ //需要将A[i]插入有序增量子表 
                A[0]=A[i];          //暂存在A[0] 
                for(j=i-d; j>0 && A[0]<A[j]; j-=d) 
                    A[j+d]=A[j];    //记录后移,查找插入位置 
                A[j+d]=A[0];        //插入 
            }
  }

交换排序

冒泡排序

//交换
  void swap(int &a,int &b){
    int temp = a;
    a = b;
    b = temp;
  } 
  //冒泡排序
  void BubbleSort(int A[], int n){
    for(int i=0; i<n-1; i++){
        bool flag = false;          //表示本趟冒泡是否发生交换的标志 
        for(int j=n-1; j>i; j--) //一趟冒泡过程 
            if(A[j-1] > A[j]){       //若为逆序 
                swap(A[j-1],A[j]);  //交换 
                flag = true;
            }
        if(flag == false)
            return                  //本趟遍历后没有发生交换,说明表已经有序 
    }
  }

快速排序

//用第一个元素将待排序序列划分成左右两个部分
  int Partition(int A[], int low, int high){
    int pivot = A[low];     //第一个元素作为枢轴 
    while(low<high){     //用low、high搜索枢轴的最终位置 
        while(low<high&&A[high]>=pivot)   --high;
        A[low] = A[high];   //比枢轴小的元素移动到左端 
        while(low<high&&A[low]<=pivot)    ++low;
        A[high] = A[low];   //比枢轴大的元素移动到右端 
    }
    A[low] = pivot;         //枢轴元素存放到最终位置 
    return low;             //返回存放枢轴的最终位置 
  } 
  //快速排序
  void QuickSort(int A[], int low, int high){
    if(low<high){    //递归跳出的条件 
        int pivotpos = Partition(A,low,high);   //划分     
        QuickSort(A,low,pivotpos-1);    //划分左子表 
        QuickSort(A,pivotpos+1,high);   //划分右子表 
    }
  }

选择排序

选择排序:每一趟在待排序元素中选取关键字最小(或最大)的元素加入有序子序列

简单选择排序

//简单选择排序
  void SelectSort (int A[],int n){
    for(int i=0; i<n-1;i++){     //一共进行n-1躺 
        int min=i;                  //记录最小元素位置 
        for(int j=i+1; j<n; j++) //在A[i...n-1]中选择最小的元素 
            if(A[j]<A[min])  min=j;  //更新最小元素位置 
        if(min!=i) swap(A[i],A[min]);//封装的swap()函数共移动元素3次 
    }
  } 
  //交换
  void swap(int &a,int &b){
    int temp = a;
    a = b;
    b = temp;
  }

堆排序

//建立大根堆
  void BuildMaxHeap(int A[], int len){
    for(int i=len/2; i>0; i--)   //从后往前调整所有非终端结点
        HeadAdjust(A,i,len); 
  } 
  //将以k为根的子树调整为大根堆
  void HeadAdjust(int A[],int k, int len){
    A[0]=A[k];                      //A[0]暂存子树的根结点 
    for(int i=2*k; i<=len; i*=2){    //沿key较大的子结点向下筛选 
        if(i<len&&A[i]<A[i+1])
            i++;                    //取key较大的字结点的下标 
        if(A[0]>=A[i])   break;      //筛选结束 
        else{       
            A[k] = A[i];            //将A[i]调整到双亲结点下 
            k = i;                  //修改k值,以便向下继续筛选 
        }   
    }
    A[k] = A[0];                    //被筛选结点的值放入最终位置 
  } 
  //完整逻辑
  void HeapSort(int A[], int len){
    BuildMaxHeap(A,len);        //初始建堆 
    for(int i=len; i>1; i--){    //n-1躺的交换和建堆过程 
        swap(A[i],A[1]);        //把堆顶元素和堆底元素交换 
        HeadAjdust(A,1,i-1);    //把剩余的待排序元素整理成堆 
    }
  }

归并排序和基数排序

归并排序

//归并排序
  int *B = (int *)malloc(n*sizeof(int)); //辅助数组B
  //A[low...mid]和A[mid+..high]各自排序,将两个部分归并
  void Merge(int A[], int low, int mid, int high){
    int i,j,k;
    for(k=low; k<=high; k++)
        B[k] = A[k];        //将A中所有元素复制到B中
    for(i=low,j=mid+1,k=i; i<=mid&&j<=high; k++){
        if(B[i] <= B[j])
            A[k] = B[i++];  //将较小值复制到A中
        else
            A[k] = B[j++]; 
    }//if 
    while(j<=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);      //归并 
    }//if 
  }
版权声明:除特殊说明,博客文章均为大块肌原创,依据CC BY-SA 4.0许可证进行授权,转载请附上出处链接及本声明。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇