數(shù)據(jù)結(jié)構(gòu)與算法月考復(fù)習(xí)

二叉樹(shù)性質(zhì)

  • 在非空二叉樹(shù)的第i層上衷敌,至多有2(i - 1)個(gè)結(jié)點(diǎn)(i>=1)
#include <math.h> //注意引入頭文件
printf("請(qǐng)輸入層數(shù):");
int i;
scanf("%d", &i);
printf("第%d層最多有%d個(gè)結(jié)點(diǎn)", i, pow(2, i - 1));
  • 在深度為K的二叉樹(shù)上最多有2k -1 個(gè)結(jié)點(diǎn)(k>=1)
printf("請(qǐng)輸入層數(shù):");
int k;
scanf("%d", &k);
printf("前%d層最多有%d個(gè)結(jié)點(diǎn)", k, pow(2, k) - 1);
  • 在任意一棵二叉樹(shù)中,葉子結(jié)點(diǎn)的數(shù)目比度數(shù)為2的結(jié)點(diǎn)的數(shù)目多1,n0 = n2 + 1
printf("請(qǐng)輸入度為1的結(jié)點(diǎn)個(gè)數(shù)一屋,及度為2的結(jié)點(diǎn)個(gè)數(shù)統(tǒng)計(jì)總結(jié)點(diǎn)個(gè)數(shù):");
int n0; //度為0的結(jié)點(diǎn)個(gè)數(shù)
int n1; //度為1的結(jié)點(diǎn)個(gè)數(shù)
int n2; //度為2的結(jié)點(diǎn)個(gè)數(shù)
scanf("%d %d", &n1, &n2);
n0 = n2 + 1; //葉子結(jié)點(diǎn)的數(shù)目比度數(shù)為2的結(jié)點(diǎn)的數(shù)目多1
printf("總的結(jié)點(diǎn)個(gè)數(shù)是%d\n", n0 + n1 + n2);
  • 具有n個(gè)結(jié)點(diǎn)的完全二叉樹(shù)的深度為 【log2n】 + 1
printf("請(qǐng)輸入完全二叉樹(shù)的結(jié)點(diǎn)個(gè)數(shù)");
int n;
scanf("%d", &n);
printf("具有%d個(gè)結(jié)點(diǎn)的完全二叉樹(shù)的深度為%d", n, (int)log2(n) + 1)

二叉樹(shù)創(chuàng)建

結(jié)點(diǎn)類(lèi)型為字符型

typedef struct node {
    char data; //數(shù)據(jù)
    node *left; //左孩子指針
    node *right; //右孩子指針
}node;

//定義創(chuàng)建函數(shù)
node* create()
{
    printf("請(qǐng)輸入結(jié)點(diǎn)的值");
    char ch;
    scanf("%c", &ch);
    //注意:如果考試過(guò)程中一次性錄入所有結(jié)點(diǎn)的值(包括#)則不需要吸收回車(chē)
    //否則如果是一個(gè)結(jié)點(diǎn)一個(gè)結(jié)點(diǎn)的錄入則選喲吸收
    getchar(); //吸收回車(chē)
    if (ch == '#') //如果輸入的#表示為空
    {
        return NULL;
    }
    //1.創(chuàng)建根結(jié)點(diǎn)
    node *root = (node*) malloc(sizeof(node)); 
    if (root == NULL)
    {
        return NULL;
    }
    //創(chuàng)建根結(jié)點(diǎn)擎值,或者(node*) malloc(100));
    root->data = ch; //給根結(jié)點(diǎn)賦值
    root->left = create(); //遞歸創(chuàng)建左子樹(shù)
    root->right = create(); //遞歸創(chuàng)建右子樹(shù)
    return root; //返回根結(jié)點(diǎn)
}

結(jié)點(diǎn)類(lèi)型為整型的情況

typedef struct node {
    int data; //數(shù)據(jù)
    node *left; //左孩子指針
    node *right; //右孩子指針
}node;

//定義創(chuàng)建函數(shù)
node* create()
{
    printf("請(qǐng)輸入結(jié)點(diǎn)的值");
    int ch;
    scanf("%d", &ch);
    if (ch == -1) //如果輸入的-1表示為空
    {
        return NULL;
    }
    //1.創(chuàng)建根結(jié)點(diǎn)
    node *root = (node*) malloc(sizeof(node)); 
    if (root == NULL)
    {
        return NULL;
    }
    //創(chuàng)建根結(jié)點(diǎn),或者(node*) malloc(100));
    root->data = ch; //給根結(jié)點(diǎn)賦值
    root->left = create(); //遞歸創(chuàng)建左子樹(shù)
    root->right = create(); //遞歸創(chuàng)建右子樹(shù)
    return root; //返回根結(jié)點(diǎn)
}

結(jié)點(diǎn)類(lèi)型為字符串的情況

typedef struct node {
    char data[100]; //數(shù)據(jù)
    node *left; //左孩子指針
    node *right; //右孩子指針
}node;

//定義創(chuàng)建函數(shù)
node* create()
{
    printf("請(qǐng)輸入結(jié)點(diǎn)的值"); //如果考試的時(shí)候只出現(xiàn)了一次則放在主函數(shù)里面
    char str[100];
    scanf("%s", str);
    if (strcmp(str, "#") == 0) //如果輸入的#表示為空
    {
        return NULL;
    }
    //1.創(chuàng)建根結(jié)點(diǎn)
    node *root = (node*) malloc(sizeof(node)); 
    if (root == NULL)
    {
        return NULL;
    }
    //創(chuàng)建根結(jié)點(diǎn)鲫忍,或者(node*) malloc(100));
    strcpy(root->data, str); //給根結(jié)點(diǎn)賦值(必須使用函數(shù)的形式)
    root->left = create(); //遞歸創(chuàng)建左子樹(shù)
    root->right = create(); //遞歸創(chuàng)建右子樹(shù)
    return root; //返回根結(jié)點(diǎn)
}

如何調(diào)用

//第一種情況:在菜單外面初始化
node *root = create();

//第二種情況
//在case里面初始化
node *root; //這句話放在while(1)的外面
//在case里面吧執(zhí)行
root = create();

二叉樹(shù)的遍歷

  • 先序遍歷(先根膏燕,再左子樹(shù),再右子樹(shù))
    void preOrder(node *root) //
    {
        if (root != NULL)
        {
            printf("%c\t", root->data); //如果是字符串類(lèi)型則%c改為%s
            preOrder(root->left); //遞歸遍歷左子樹(shù)
            preOrder(root->right); //遞歸遍歷右子樹(shù)
        }
    }

    //調(diào)用形式
    preOrder(root);
  • 中序遍歷(先左子樹(shù)悟民,再根坝辫,再右子樹(shù))

    void inOrder(node *root)
    {
        if (root != NULL)
        {
            inOrder(root->left); //遞歸訪問(wèn)左子樹(shù)
            printf("%c\t", root->data); //如果是字符串類(lèi)型則%c改為%s
            inOrder(root->right); //遞歸訪問(wèn)右子樹(shù)
        }
    }
    
    
    //調(diào)用形式
    inOrder(root);
    
  • 后序遍歷(先左子樹(shù),再右子樹(shù)射亏,再根)

    void postOrder(node *root)
    {
        if (root != NULL)
        {
            postOrder(root->left); //遞歸訪問(wèn)左子樹(shù)
            postOrder(root->right); //遞歸訪問(wèn)右子樹(shù)
            printf("%c\t", root->data); //如果是字符串類(lèi)型則%c改為%s
        }
    }
    
    //調(diào)用形式
    postOrder(root);
    

    判斷兩棵二叉樹(shù)是否相同

    • 判斷兩棵二叉樹(shù)是否為空近忙,如果都是空則表明相同

    • 如果有一顆為空,另外一顆不為空則表明不相同

    • 如果都不為空智润,則判斷根是否相同及舍,如果相同繼續(xù)判斷左子樹(shù)和右子樹(shù)是否都相同,如果都相同的情況下則表明兩棵二叉樹(shù)是相同的

      //判斷兩棵二叉樹(shù)是否相同,如果相同返回1窟绷,否則返回0
      int isSame(node *root1, node *root2)
      {
          if (root1 == NULL && root2 == NULL)
          {
              return 1;
          }
          else if(root1 == NULL || root2 == NULL)
          {
              return 0; //如果有一顆為空锯玛,另外一顆不為空則表明不相同
          }
          else //兩棵樹(shù)都不為空
          {
              if (root1->data == root2->data) //比較兩棵樹(shù)的數(shù)據(jù)域是否相同
              {
                  //如果根相同則還要遞歸比較左子樹(shù)和右子樹(shù)
                  //只有根和左子樹(shù)和右子樹(shù)都相同的情況那么整顆樹(shù)一定是相等
                  return isSame(root1->left, root2->left) && isSame(root1->right, root2->right);
              }
              else
              {
                  return 0; //如果對(duì)應(yīng)的根不相等則表示不相同
              }
          }
      }
      

      求二叉樹(shù)的高度

      • 求解出左子樹(shù)的高度
      • 求解出右子樹(shù)的高度
      • 比較左子樹(shù)和右子樹(shù)的高度,把較大的一個(gè)高度 + 1就是整顆二叉樹(shù)的高度
      //求出二叉樹(shù)的高度
      int gao(node *root)
      {
          if (root == NULL)
          {
              return 0; //為空的二叉樹(shù)高度為0
          }
          //把根節(jié)點(diǎn)的左指針作為參數(shù)兼蜈,求解出左子樹(shù)的高度
          int h1 = gao(root->left); 
          //把根結(jié)點(diǎn)右指針作為參數(shù)攘残,求解出右子樹(shù)的高度
          int h2 = gao(root->right);
          if (h1 > h2)
          {
              return h1 + 1; //+1因?yàn)橐由细Y(jié)點(diǎn)這一層
          }
          else
          {
              return h2 + 1;
          }
      }
      

      求解二叉樹(shù)中葉子結(jié)點(diǎn)的個(gè)數(shù)

      • 求出左子樹(shù)的葉子結(jié)點(diǎn)個(gè)數(shù)
      • 求出右子樹(shù)的葉子結(jié)點(diǎn)個(gè)數(shù)
      • 把左子樹(shù)的葉子結(jié)點(diǎn) + 右子樹(shù)的結(jié)點(diǎn)個(gè)數(shù) 就是整顆樹(shù)的結(jié)點(diǎn)個(gè)數(shù)
      //統(tǒng)計(jì)二叉樹(shù)中葉子結(jié)點(diǎn)的個(gè)數(shù)
      int count(node *root)
      {
          if (root == NULL)
          {
              return 0;
          }
          else if(root->left == NULL && root->right == NULL)
          {
              return 1; //如果左子樹(shù)和右子樹(shù)同時(shí)為空則表明找到一個(gè)葉子
          }
          else
          {
              //總的葉子結(jié)點(diǎn)個(gè)數(shù)等于左子樹(shù)的葉子結(jié)點(diǎn)個(gè)數(shù) + 右子樹(shù)的葉子結(jié)點(diǎn)個(gè)數(shù)
              return count(root->left) + count(root->right);
          }
      } 
      

      求出二叉樹(shù)中所有結(jié)點(diǎn)的個(gè)數(shù)

      • 求出左子樹(shù)的結(jié)點(diǎn)個(gè)數(shù)
      • 求出右子樹(shù)的結(jié)點(diǎn)個(gè)數(shù)
      • 總的結(jié)點(diǎn)個(gè)數(shù) = 左子樹(shù)的結(jié)點(diǎn)個(gè)數(shù) + 右子樹(shù)的結(jié)點(diǎn)個(gè)數(shù) + 1
      //統(tǒng)計(jì)所有結(jié)點(diǎn)的個(gè)數(shù)
      int count(node *root)
      {
          if (root == NULL)
          {
              return 0; //如果根為空返回0
          }
          else
          {
              return 1 + count(root->left) + count(root->right);
          }
      }
      

      統(tǒng)計(jì)二叉樹(shù)中所有度為1的結(jié)點(diǎn)個(gè)數(shù)(只有一個(gè)孩子)

      int count(node *root)
      {
          if (root == NULL)
          {
              return 0;
          }
          if(root->left != NULL && root->right != NULL)
          {
              //如果根節(jié)點(diǎn)的左子樹(shù)和右子樹(shù)都不為空
              //則整顆樹(shù)中度為1的結(jié)點(diǎn)個(gè)數(shù) = 左邊的 + 右邊的
              return count(root->left) + count(root->right);
          }
          else if(root->left == NULL && root->right == NULL) 
          {
              //如果左右都為空
              return 0;
          }
          else //要么左子樹(shù)樹(shù)為空,要么右子樹(shù)為空
          {
              return 1 + count(root->left) + count(root->right);
          }
      }
      

#define N 8 //表示圖中頂點(diǎn)的個(gè)數(shù)

typedef struct {
    char vertex[N][100]; //存儲(chǔ)頂點(diǎn)信息
    int edge[N][N]; //存儲(chǔ)頂點(diǎn)之間邊的關(guān)系
}graph; // 定義圖形結(jié)構(gòu)體

//初始化圖
void init(graph *g)
{
    //1.先初始化頂點(diǎn)
    for (int i = 0; i < N; i++)
    {
        strcpy(g->vertex[i], "空");
    }
    //2.初始化所有的邊為0
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            g->edge[i][j] = 0;
        }
    }
}

//插入頂點(diǎn)(插入頂點(diǎn)和插入邊要分開(kāi))为狸,不然被扣分
void insertVertex(graph *g)
{
    for (int i = 0; i < N; i++)
    {
        printf("請(qǐng)輸入第%d個(gè)頂點(diǎn):", i + 1);
        scanf("%s", g->vertex[i]);
    }
}


//插入邊(單詞可以隨意)
void insertEdge(graph *g)
{
    //插入邊要考慮到優(yōu)化

    //1.如果是有向圖不能優(yōu)化歼郭,最多優(yōu)化自生到自身的邊
    //2.如果是無(wú)向圖可以優(yōu)化


    //無(wú)任何優(yōu)化的版本(即沒(méi)有優(yōu)化自身到自身,也沒(méi)有實(shí)現(xiàn)對(duì)稱(chēng)的性質(zhì))

    //下面的三個(gè)循環(huán)用一個(gè)就行了辐棒,別全干上去好吧病曾,看效果圖到底用哪個(gè)
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            printf("若頂點(diǎn)%s到頂點(diǎn)%s之間存在邊則輸入1,否則輸入0:", g->vertex[i], g->vertex[j]);
            scanf("%d", &g->edge[i][j]);
        }
    }

    //只過(guò)濾自身結(jié)點(diǎn)到自身結(jié)點(diǎn)的邊(過(guò)濾對(duì)角線的輸入)
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            if (i != j)
            {
                printf("若頂點(diǎn)%s到頂點(diǎn)%s之間存在邊則輸入1,否則輸入0:", g->vertex[i], g->vertex[j]);
                scanf("%d", &g->edge[i][j]);
            }
        }
    }

    //全部?jī)?yōu)化(包括對(duì)角線及對(duì)稱(chēng)賦值)
    for (int i = 0; i < N - 1; i++)
    {
        for (int j = i + 1; j < N; j++)
        {
            printf("若頂點(diǎn)%s到頂點(diǎn)%s之間存在邊則輸入1,否則輸入0:", g->vertex[i], g->vertex[j]);
            scanf("%d", &g->edge[i][j]);
            g->edge[j][i] = g->edge[i][j]; //對(duì)稱(chēng)賦值
        }
    }
}


//打印圖的鄰接矩陣
void output(graph *g)
{
    //打印頂點(diǎn)元素
    printf("頂點(diǎn)元素如下:\n");
    for (int i = 0; i < N; i++)
    {
        printf("%s\t", g->vertex[i]);
    }
    printf("\n");

    printf("邊矩陣如下:\n");
    for (int i = 0; i < N; i++)
    {
        printf("\t%s", g->vertex[i]);
    }
    printf("\n");

    for (int i = 0; i < N; i++)
    {
        printf("%s\t", g->vertex[i]);
        for (int j = 0; j < N; j++)
        {
            printf("%d\t", g->edge[i][j]);
        }
        printf("\n");
    }
}

//如何調(diào)用圖
int main()
{
    graph g; 
    init(&g); //初始化圖
    insertVertex(&g); //插入頂點(diǎn)
    insertEdge(&g); //插入邊
    output(&g); //打印圖
}

計(jì)算圖中每個(gè)頂點(diǎn)的入度(對(duì)應(yīng)粉絲量)

//注意:入度計(jì)算鄰接矩陣姊途,對(duì)應(yīng)頂點(diǎn)的列之和
void count(graph *g)
{
    for (int i = 0; i < N; i++)
    {
        int sum = 0; //統(tǒng)計(jì)入度(統(tǒng)計(jì)列之和)
        for (int j = 0; j < N; j++)
        {
            sum = sum + g->edge[j][i]; //按照列遍歷二維數(shù)組
        }
        printf("頂點(diǎn)%s的入度是%d\n", g->vertex[i], sum);
        //printf("用戶%s的粉絲量是%d\n", g->vertex[i], sum);
    }
}

計(jì)算圖中每個(gè)頂點(diǎn)的出(對(duì)應(yīng)關(guān)注量)

//注意:入度計(jì)算鄰接矩陣,對(duì)應(yīng)頂點(diǎn)的列之和
void count(graph *g)
{
    for (int i = 0; i < N; i++)
    {
        int sum = 0; //統(tǒng)計(jì)出度(統(tǒng)計(jì)行之和)
        for (int j = 0; j < N; j++)
        {
            sum = sum + g->edge[i][j]; //按照行遍歷二維數(shù)組
        }
        printf("頂點(diǎn)%s的出度是%d\n", g->vertex[i], sum);
        //printf("用戶%s的關(guān)注量是%d\n", g->vertex[i], sum);
    }
}

同時(shí)統(tǒng)計(jì)出每個(gè)頂點(diǎn)的入度和出度(粉絲量和關(guān)注量)

void count(graph *g)
{
    for (int i = 0; i < N; i++)
    {
        int sum1 = 0; //統(tǒng)計(jì)入度
        int sum2 = 0; //統(tǒng)計(jì)出度
        for (int j = 0; j < N; j++)
        {
            sum1 = sum1 + g->edge[j][i]; 
            sum2 = sum2 + g->edge[i][j]
        }
        printf("頂點(diǎn)%s的入度是%d\n", g->vertex[i], sum1);
        printf("頂點(diǎn)%s的出度是%d\n", g->vertex[i], sum2);
        printf("頂點(diǎn)%s的度是%d\n", g->vertex[i], sum1 + sum2); //度=入度+出度
    }
}

求出圖中度最大值頂點(diǎn)信息

void max(graph  *g)
{
    //假設(shè)第一個(gè)頂點(diǎn)的度最大
    int max = 0;
    int maxi = 0; //記錄最大值的下標(biāo)
    for (int i = 0; i < N; i++)
    {
        max = max + g->edge[0][i] + g->edge[i][0]; //求出第一行和最后一個(gè)行
    }

    for (int i = 0; i < N; i++)
    {
        int sum = 0; //記錄頂點(diǎn)vertex[i]的度(入度和出度)
        for (int j = 0; j < N; j++)
        {
            sum = sum + g->edge[i][j] + g->edge[j][i]; //統(tǒng)計(jì)第i行和第i列之和
        }
        if (sum > max) //求最大值
        {
            max = sum; //更新最大值
            maxi = i; //更新最大值的下標(biāo)
        }
    }
    printf("度值最大值頂點(diǎn)是%s,他的度是是%d\n", g->vertex[maxi], max);
}

求出圖中入度最大的頂點(diǎn)(求出粉絲量多的用戶)

void max(graph *g)
{
    //假設(shè)第一個(gè)頂點(diǎn)的入度最大值
    int max = 0;
    int maxi = 0; //記錄最大值的下標(biāo)
    for (int i = 0; i < N; i++)
    {
        max = max + g->edge[i][0]; //求出第一行和最后一個(gè)行
    }

    for (int i = 0; i < N; i++)
    {
        int sum = 0; 
        for (int j = 0; j < N; j++)
        {
            sum = sum + g->edge[j][i]; 
        }
        if (sum > max) //求最大值
        {
            max = sum; //更新最大值
            maxi = i; //更新最大值的下標(biāo)
        }
    }
    printf("入度值最大值頂點(diǎn)是%s,他的入度是是%d\n", g->vertex[maxi], max);
    printf("用戶%s的粉絲量最多,他的粉絲量為%d\n", g->vertex[maxi], max);
}

求出圖中出度最大的頂點(diǎn)(求出關(guān)注量多的用戶)

void max(graph *g)
{
    //假設(shè)第一個(gè)頂點(diǎn)的入度最大值
    int max = 0;
    int maxi = 0; //記錄最大值的下標(biāo)
    for (int i = 0; i < N; i++)
    {
        max = max + g->edge[0][i]; //求出第一行和最后一個(gè)行
    }

    for (int i = 0; i < N; i++)
    {
        int sum = 0; 
        for (int j = 0; j < N; j++)
        {
            sum = sum + g->edge[i][j]; 
        }
        if (sum > max) //求最大值
        {
            max = sum; //更新最大值
            maxi = i; //更新最大值的下標(biāo)
        }
    }
    printf("出度值最大值頂點(diǎn)是%s,他的出度是是%d\n", g->vertex[maxi], max);
    printf("用戶%s的關(guān)注量最多,他的關(guān)注量為%d\n", g->vertex[maxi], max);
}

深度優(yōu)先搜索代碼

int v[N]; //默認(rèn)是0知态,記錄每個(gè)頂點(diǎn)是否被訪問(wèn)過(guò)的狀態(tài)
void dfs(graph *g, int start) //start為起始頂點(diǎn)的下標(biāo)
{
    printf("%s\t", g->vertex[start]); //打印下表為start的頂點(diǎn)
    v[start] = 1; //表示Vi被訪問(wèn)過(guò)了
    //下一步捷兰,找vi未被訪問(wèn)過(guò)的鄰接點(diǎn)作為起始點(diǎn),注意鄰接點(diǎn)一定位于start下標(biāo)這一行
    for (int i = 0; i < N; i++)
    {
        if (g->edge[start][i] == 1 && v[i] == 0)
        {
            dfs(g, i); //把i下標(biāo)作為新的起始點(diǎn)出發(fā)深度優(yōu)先搜索
        }
    }
}

打印圖的所有路徑

//定義棧
typedef struct {
    char data[N][100]; //存放N個(gè)頂點(diǎn)
    int top
}stack;

//入棧
int push(stack *s, char e[])
{
    if (s->top == N - 1)
    {
        return 0; //棧滿
    }
    s->top++;
    strcpy(s->data[s->top], e); //入棧
    return 1; //入棧成功
}

//出棧
int pop(stack *s)
{
    if (s->top == -1)
    {
        return 0; //出棧失敗
    }
    s->top--;
    return 1;
}

int flag = 0; //標(biāo)記是否有路徑

//打印棧
void outputStack(stack *s)
{
    flag = 1; //表示有路徑
    for (int i = 0; i < s->top; i++) //打印最下面n-1個(gè)
    {
        printf("%s----->", s->data[i]);
    }
    printf("%s\n", s->data[s->top]); //打印最上面的一個(gè)
}

int v[N]; //記錄每個(gè)頂點(diǎn)是否被訪問(wèn)過(guò)

//定義查找所有路徑函數(shù)
void path(graph *g, stack *s, int start, int end)
{
    //把起始點(diǎn)入棧
    push(s, g->vertex[start]); //把vertex[start]起始點(diǎn)入棧
    v[start] = 1; //把vertex[start] 標(biāo)記為被訪問(wèn)過(guò)

    if (start == end) 
    {
        //如果當(dāng)前的起始點(diǎn)和終止點(diǎn)相同负敏,則表示找到一條路徑
        //打印棧的內(nèi)容就是一條完整的路徑
        outputStack(s);
        //把棧頂元素彈出贡茅,從新回溯到上一個(gè)被訪問(wèn)過(guò)的頂點(diǎn)
        pop(s); //彈出棧,每次只能夠彈出一個(gè)
        //并且彈出的棧頂元素標(biāo)記為未被訪問(wèn)過(guò)
        v[end] = 0; //或者v[start] = 0;
        return; //return必須加入,不然不行
    }   

    //那么如果起始點(diǎn)和終止點(diǎn)不一樣呢
    //則找頂點(diǎn)vertex[start]的鄰接點(diǎn)作為起始點(diǎn)出發(fā)其做,找到終止點(diǎn)
    //vertex[end]的路徑
    for (int i = 0; i < N; i++)
    {
        //找未被訪問(wèn)過(guò)的鄰接點(diǎn)
        if (g->edge[start][i] == 1 && v[i] == 0)
        {
            //原先是從vertex[start] -> vertex[end]的路徑
            //現(xiàn)在把問(wèn)題轉(zhuǎn)換成從vertex[i] -> vertex[end] 的路徑
            path(g, s, i, end);
        }
    }
    //如果沒(méi)有找到vertex[start] 的鄰接點(diǎn)
    //則需要?jiǎng)h除棧頂元素回溯到上一個(gè)被訪問(wèn)的鄰接點(diǎn)
    //繼續(xù)找上一個(gè)被訪問(wèn)的頂點(diǎn)的未被訪問(wèn)過(guò)的鄰接點(diǎn)
    pop(s); //出棧
    v[strat] = 0; //或者v[s->top] = 0;
}


//調(diào)用方式
int main()
{
    graph g; //初始化圖
    stack s;
    s.top = -1; //初始化棧
    printf("請(qǐng)輸入起始和終止的下標(biāo):");
    int start;
    int end;
    scanf("%d %d", &start, &end);

    path(&g, &s, start, end);
    if (flag == 0)
    {
        printf("頂點(diǎn)%s到頂點(diǎn)%s之間沒(méi)有路徑\n", g->vertex[start], g->vertex[end]);
    }
}

順序表的定義

typedef struct {
    char name[100]; //姓名
    int age; //年齡
    int score; //成績(jī)
}stu;

#define MAX
typedef struct {
    stu data[MAX];
    int len;
}list;

順序查找

對(duì)數(shù)組進(jìn)行順序查找(整數(shù)數(shù)組)

//在數(shù)組arr中查找關(guān)鍵詞key的位置,并且返回下標(biāo)
int search(int arr[], int len, int key)
{
    for (int i = 0; i < len; i++)
    {
        if (key == arr[i])
        {
            return i;
        }
    }
    return -1;
}

對(duì)結(jié)構(gòu)體數(shù)組進(jìn)行順序查找

//在結(jié)構(gòu)體數(shù)組中查找特定姓名的下標(biāo)
int search(stu arr[], int len, char name[])
{
    for (int i = 0; i < len; i++)
    {
        if (strcmp(arr[i].name, name) == 0)
        {
            return i;
        }
    }
    return -1;
}

對(duì)順序表進(jìn)行順序查找

//在順序表中查找姓名為name的人顶考,并且返回下標(biāo)
int search(list *l, char name[])
{
    for (int i = 0; i < l->len; i++)
    {
        if (strcmp(l->arr[i].name, name) == 0)
        {
            return i;
        }
    }
    return -1;
}

順序表的優(yōu)化版本(哨兵優(yōu)化),僅對(duì)順序表進(jìn)行舉例子

//順序表的哨兵法查找
int search(list *l, char name[])
{
    if (strcmp(l->data[0].name, name) == 0)
    {
        return 0; //如果第一個(gè)剛好就是,則返回
    }
    stu temp = l->data[0];//保存第一元素
    strcpy(l->data[0].name, name); //把第一個(gè)元素的名稱(chēng)更改為要查找的名稱(chēng)妖泄,這樣子從右邊往左邊掃描驹沿,如果提前找到則成功,如果沒(méi)有找到蹈胡,那么由于我們?cè)诘谝粋€(gè)位置設(shè)置了哨兵元素(即我們要查找的元素)渊季,所以當(dāng)找到一個(gè)元素的時(shí)候,循環(huán)就自動(dòng)結(jié)束了(查找失敗)
    int j = l->len - 1; //最后一個(gè)元素的下標(biāo)
    while (strcmp(l->data[j].name, name) != 0)
    {
        j--; //只要不相等則不斷掃描
    }
    l->data[0] = temp; //還原我們?cè)O(shè)置的哨兵位置的元素值
    if (j == 0)
    {
        //如果等于0表示找到的是我們?cè)O(shè)置的哨兵
        return -1; //失敗
    }
    else
    {
        return j; //成功
    }
}

折半查找

  • 前提: 數(shù)組有序(必須先排序)

對(duì)普通數(shù)組進(jìn)行折半查找

//折半查找查找key在數(shù)組中的下標(biāo)
int search(int arr[], int len, int key)
{
    int low = 0; //低下標(biāo)
    int high = len - 1; //高下標(biāo)
    while (low <= high)
    {
        int mid = (low + high) / 2; //計(jì)算中間元素的下標(biāo)
        if(key == arr[mid])
        {
            return mid; //如果要查找的元素剛好位置中間則返回
        }
        else if (key < arr[mid]) //如果是降序罚渐,則改為 > 
        {
            //如果小于中間元素則去左邊找却汉,區(qū)間范圍[low, mid - 1]
            high = mid - 1;
        }
        else
        {
            //如果大于中間元素則去右邊找,區(qū)間范圍[mid + 1, high]
            low = mid + 1; //更新第下標(biāo)
        }
        //循環(huán)再次回去重新計(jì)算中間下標(biāo)
    }
    return -1; //查找失敗
}

對(duì)順序表進(jìn)行折半查找

//對(duì)順序表進(jìn)行折半查找荷并,注意查找之前必須排序
int search(list *l, char name[])
{
    int low = 0;
    int high = l->len - 1;
    while (low <= high)
    {
        int mid = (low + high) / 2;
        if (strcmp(name, l->data[mid].name) == 0)
        {
            return mid;
        }
        else if(strcmp(name, l->data[mid].name) < 0)
        {
            high = mid - 1;
        }
        else
        {
            low = mid + 1;
        }
    }
    return -1;
}

二叉排序樹(shù)的構(gòu)造

構(gòu)造數(shù)據(jù)類(lèi)型為整型的二叉排序樹(shù)


typedef struct node{
    int data; //數(shù)據(jù)
    node *left; //左孩子 
    node *right; //右孩子
}node;

//定義創(chuàng)建二叉排序樹(shù)根的函數(shù)
node *create(int data) //把第一個(gè)結(jié)點(diǎn)值作為根
{
    node *root = (node*) malloc(sizeof(node)); //創(chuàng)建根
    if (root == NULL)
    {
        return NULL; //如果創(chuàng)建失敽仙啊(幾率很小)則返回空
    }
    root-data = data; //賦值
    root->left = root->right = NULL; //左孩子和右孩子均為空
    return root; //返回根
}

//定義結(jié)點(diǎn)插入函數(shù)源织,插入結(jié)點(diǎn)構(gòu)造二叉排序樹(shù)
void insert(node *root, int data)
{
    if (data < root->data)
    {
        //如果小于根翩伪,則插入到左子樹(shù)上

        //1.如果左子樹(shù)為空,則直接插入
        if (root->left == NULL)
        {
            node *newNode = (node*)malloc(sizeof(node)); //創(chuàng)建新結(jié)點(diǎn)便于插入
            newNode->data = data; //給新的結(jié)點(diǎn)賦值
            newNode->left = newNode->right = NULL; //讓新的結(jié)點(diǎn)左子樹(shù)和右子樹(shù)均為空

            root->left = newNode; //把創(chuàng)建完成的新結(jié)點(diǎn)的地址賦值給根的左指針
        }
        else
        {
             //2.如果左子樹(shù)不為空谈息,則要遞歸找一個(gè)為空位置
             insert(root->left, data); //遞歸插入到左子樹(shù)上
        }

       
    }
    else if (data > root->data)
    {
        //如果大于根缘屹,則插入到右子樹(shù)上面
        //1.如果右子樹(shù)為空,則直接插入
        if (root->right == NULL)
        {
            node *newNode = (node*)malloc(sizeof(node)); //創(chuàng)建新結(jié)點(diǎn)便于插入
            newNode->data = data; //給新的結(jié)點(diǎn)賦值
            newNode->left = newNode->right = NULL; //讓新的結(jié)點(diǎn)左子樹(shù)和右子樹(shù)均為空

            root->right = newNode; //把創(chuàng)建完成的新結(jié)點(diǎn)的地址賦值給根的右指針
        }
        else
        {
             //2.如果右子子樹(shù)不為空黎茎,則要遞歸找一個(gè)為空位置
             insert(root->right, data); //遞歸插入到右子樹(shù)上
        }

    }
    else
    {
        printf("和根節(jié)點(diǎn)相等囊颅,數(shù)據(jù)不合法\n");
        //二叉排序樹(shù)中不存在相同的結(jié)點(diǎn)值
    }

}

//二叉樹(shù)的中序遍歷
void inOrder(node *root)
{
    if (root != NULL)
    {
        inOrder(root->left); //遞歸訪問(wèn)左子樹(shù)
        printf("%d\t", root->data); 
        inOrder(root->right); //遞歸訪問(wèn)右子樹(shù)
    }
}


//如何調(diào)用
int main()
{
    int arr[7] = {19, 14, 22, 66, 21, 83, 10}; //可以從鍵盤(pán)錄入
    node *root = create(arr[0]); //把第一個(gè)結(jié)點(diǎn)作為根

    //一次把第arr[1]  到 arr[6]插入到二叉樹(shù)里面
    for (int i = 1; i < 7; i++)
    {
        insert(root, arr[i]); //依次把a(bǔ)rr[i]插入到二叉樹(shù)里面
    }

    printf("二叉排序樹(shù)的中序遍歷\n");
    inOrder(root); //10 14 19 21 22 66 83
}

哈希表代碼

//已知一組關(guān)鍵字序列為(25当悔,51傅瞻,8,22盲憎,26嗅骄,67,11饼疙,16溺森,54慕爬,41)
//將上述序列存入哈希表中,假設(shè)哈希函數(shù): H(key)=key MOD 13

#define M 13 //定義哈希表長(zhǎng)度

int hash(int key) //計(jì)算關(guān)鍵詞得哈希地值
{
    return key % M; //到底%多少看題目要求屏积,
}

//把關(guān)鍵詞key存放到哈希表里面
void put(int hashTable[], int key)
{
    int index = hash(key); //計(jì)算關(guān)鍵詞key的地址
    while (hashTable[index] != 0) //如果不為空
    {
        //則采用線性探測(cè)法解決沖突医窿,即不斷往后面找
        index = (index + 1) % M; //%M的目的是防止下標(biāo)越界
        //不可能找不到空白位置,因?yàn)楣1淼拈L(zhǎng)度大于數(shù)組的個(gè)數(shù),s
        //所以哈希表基本不可能存在滿的情況
    }

    hashTable[index] = key; //只要循環(huán)結(jié)束炊林,則表明找到空白位置了
}

int count; //統(tǒng)計(jì)查找此輸出
//查找關(guān)鍵詞key在哈希表中的位置(下標(biāo))
int search(int hashTable[], int key)
{
    int index = hash(key); //計(jì)算關(guān)鍵詞key的地址
    count = 1;
    while (hashTable[index] != 0) //如果不為空
    {
        if (hashTable[index] == key)
        {
            return index; 
        }
        index = (index + 1) % M; //%M的目的是防止下標(biāo)越界
        count++; //每次計(jì)算哈希地址姥卢,查找次數(shù) + 1
    }
    //循環(huán)結(jié)束表示查找失敗
    return -1;

}

//如何去調(diào)用
int main()
{
    int arr[10] = {25, 51, 8, 22, 26, 67, 11, 16, 54, 41};
    int hashTable[M] = {0}; //初始化一個(gè)哈希表,長(zhǎng)度為M
    for (int i = 0; i < 10; i++)
    {
        put(hashTable, arr[i]);
    }

    printf("哈表的元素值如下\n");
    for (int i = 0; i < M; i++)
    {
       printf("%d\t", hashTable[i]);
    }
    printf("\n");

    for (int i = 0; i < 10; i++)
    {
        int index = search(hashTable, arr[i]); //查找arr[i]地址
        printf("關(guān)鍵詞%d的哈希地址是%d,查找次數(shù)%d\n", arr[i], index, count);
    }
}

排序

插入排序(對(duì)數(shù)組類(lèi)型進(jìn)行排序)

//插入排序
void insertSort(int arr[], int len)
{
    for (int i = 1; i < len; i++)
    {
        int key = arr[i]; //待插入的元素值
        int j; //從有序元素的最后一位開(kāi)始掃描
        for (j = i - 1; j >= 0 && key < arr[j]; j--)
        {
            arr[j + 1] = arr[j]; //把元素往后移動(dòng)
        }
        arr[j + 1] = key; //開(kāi)始插入
    }
}

插入排序(對(duì)順序表進(jìn)行排序)

//插入排序
void insertSort(list *l, int len)
{
    for (int i = 1; i < l->len; i++)
    {
        stu key = l->data[i]; //待插入的元素值
        int j; //從有序元素的最后一位開(kāi)始掃描
        for (j = i - 1; j >= 0 && key.age < l->data[j].age; j--)
        {
            l->data[j + 1] = l->data[j]; //把元素往后移動(dòng)
        }
        l->data[j + 1] = key; //開(kāi)始插入
    }
}

希爾排序(對(duì)數(shù)組類(lèi)型進(jìn)行排序)

  • 只要把直接插入排序外面套一層循環(huán)渣聚,然后把所有的1改為外層循環(huán)變量k
//希爾排序
void shellSort(int arr[], int len)
{
    for (int k = len / 2; k > 0; k /= 2)
    {
        for (int i = k; i < len; i++)
        {
            int key = arr[i]; //待插入的元素值
            int j; //從有序元素的最后一位開(kāi)始掃描
            for (j = i - k; j >= 0 && key < arr[j]; j -= k)
            {
                arr[j + k] = arr[j]; //把元素往后移動(dòng)
            }
            arr[j + k] = key; //開(kāi)始插入
        }
    }
}

希爾排序(對(duì)順序表進(jìn)行排序)

//希爾排序
void shellSort(list *l, int len)
{
    for (int k = l->len / 2; k > 0; k /= 2)
    {

        for (int i = k; i < l->len; i++)
        {
            stu key = l->data[i]; //待插入的元素值
            int j; //從有序元素的最后一位開(kāi)始掃描
            for (j = i - k; j >= 0 && key.age < l->data[j].age; j -= k)
            {
                l->data[j + k] = l->data[j]; //把元素往后移動(dòng)
            }
            l->data[j + k] = key; //開(kāi)始插入
        }
    }
}

冒泡排序(對(duì)基本數(shù)據(jù)類(lèi)型排序)

void bubbleSort(int arr[], int len)
{
    //每經(jīng)過(guò)一趟可以得到一個(gè)最大值
    //所以只需要(n-1)就可以完成排序
    for (int i = 0; i < len - 1; i++)
    {
        int flag = 0; //標(biāo)記是否有元素交換
        for (int j = 0; j < len - 1 - i; j++)
        {
            if (arr[j] > arr[j + 1])
            {
                int t = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = t;

                flag = 1; //如果有元素交換則更改flag的值
            }
        }
        if (flag == 0) //如果某一趟沒(méi)有發(fā)生元素的交換則表明已經(jīng)有序了
        {
            break;
        }
    }
}

冒泡排序(對(duì)順序表進(jìn)行排序)

void bubbleSort(list *l)
{
    //每經(jīng)過(guò)一趟可以得到一個(gè)最大值
    //所以只需要(n-1)就可以完成排序
    for (int i = 0; i < l->len - 1; i++)
    {
        int flag = 0; //標(biāo)記是否有元素交換
        for (int j = 0; j < l->len - 1 - i; j++)
        {
            if (strcmp(l->data[j].name, l->data[j + 1].name) > 0)
            {
                stu t = l->data[j];
                l->data[j] = l->data[j + 1];
                l->data[j + 1] = t;

                flag = 1; //如果有元素交換則更改flag的值
            }
        }
        if (flag == 0) //如果某一趟沒(méi)有發(fā)生元素的交換則表明已經(jīng)有序了
        {
            break;
        }
    }
}

簡(jiǎn)單選擇排序(對(duì)數(shù)組進(jìn)行排序)

void selectionSort(int arr[], int len)
{
    //每一趟從無(wú)序元素里找最小值和無(wú)序的第一個(gè)元素交換
    for (int i = 0; i < len - 1; i++)
    {
        int min = i; //假設(shè)當(dāng)前的arr[i]是最小值
        //從區(qū)間[i + 1, len - 1] 之間找最小值
        for (int j = i + 1; j < len; j++)
        {
            if (arr[j] < arr[min])
            {
                min = j; //更新最小值下標(biāo)
            }
        }
        //交換arr[min]和arr[i]
        // if (min != i)
        // {
        //     int t = arr[min];
        //     arr[min] = arr[i];
        //     arr[i] = t;
        // }
        //如果不想用if包裹著也可以
        int t = arr[min];
        arr[min] = arr[i];
        arr[i] = t;
    }
}

簡(jiǎn)單選擇排序(對(duì)順序表)

void selectionSort(list *l)
{
    //每一趟從無(wú)序元素里找最小值和無(wú)序的第一個(gè)元素交換
    for (int i = 0; i < l->len - 1; i++)
    {
        int min = i; //假設(shè)當(dāng)前的arr[i]是最小值
        //從區(qū)間[i + 1, l->len - 1] 之間找最小值
        for (int j = i + 1; j < l->len; j++)
        {
            if (l->data[j].age < l->data[min].age)
            {
                min = j; //更新最小值下標(biāo)
            }
        }
        //如果不想用if包裹著也可以
        stu t = l->data[min];
        l->data[min] = l->data[i];
        l->data[i] = t;
    }
}

1910D班出版結(jié)束(祝大家都升班),盜版必究

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末独榴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子奕枝,更是在濱河造成了極大的恐慌棺榔,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隘道,死亡現(xiàn)場(chǎng)離奇詭異症歇,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)谭梗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)当船,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人默辨,你說(shuō)我怎么就攤上這事德频。” “怎么了缩幸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵壹置,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我表谊,道長(zhǎng)钞护,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任爆办,我火速辦了婚禮难咕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘距辆。我一直安慰自己余佃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布跨算。 她就那樣靜靜地躺著爆土,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诸蚕。 梳的紋絲不亂的頭發(fā)上步势,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天氧猬,我揣著相機(jī)與錄音,去河邊找鬼坏瘩。 笑死盅抚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的倔矾。 我是一名探鬼主播泉哈,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼破讨!你這毒婦竟也來(lái)了丛晦?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤提陶,失蹤者是張志新(化名)和其女友劉穎烫沙,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體隙笆,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锌蓄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了撑柔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瘸爽。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖铅忿,靈堂內(nèi)的尸體忽然破棺而出剪决,到底是詐尸還是另有隱情,我是刑警寧澤檀训,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布柑潦,位于F島的核電站,受9級(jí)特大地震影響峻凫,放射性物質(zhì)發(fā)生泄漏渗鬼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一荧琼、第九天 我趴在偏房一處隱蔽的房頂上張望譬胎。 院中可真熱鬧,春花似錦命锄、人聲如沸堰乔。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)浩考。三九已至,卻和暖如春被盈,著一層夾襖步出監(jiān)牢的瞬間析孽,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工只怎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留袜瞬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓身堡,卻偏偏與公主長(zhǎng)得像邓尤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贴谎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容