数据结构全部代码

本文深入讲解了数据结构的基础概念,包括线性表、栈、队列等,并详细探讨了二叉树、图论算法以及查找算法等内容。通过具体实例演示了不同数据结构的应用场景和实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据结构

1.线性表

n个数据特性相同的元素构成的有限序列称为线性表。线性表有顺序存储和链式存储两种存储结构。
	顺序表
	优点:存储密度大;可以随机存取
	.缺点:增删时需要移动大量数据;浪费存储空间;属于静态存储

1.1约瑟夫环顺序表

有n个人,输入淘汰密码m,报到这个数的人淘汰,再接着从下一个人数接着数,直到最后剩下一个人。
#include<stdio.h>
#include<stdlib.h>

typedef struct Table{
    int * head;
    int length;
    int size;
}table;

//初始化顺序表
table initTable(int size){
    table t;
    t.head=(int*)malloc(size*sizeof(int));
    if (!t.head)
    {
        printf("初始化失败\n");
        exit(0);
    }
    t.length=0;
    t.size=size;
    return t;
}
 
void DisplayList(table t1)
{
     int m, i, j;
    int k=0;
    printf("\n");
    printf("请输入淘汰密码: \n");
    scanf("%d", &m);
    printf("\n");
    printf("淘汰次序依次是:\n");
    for (i=t1.length; i>1; i--)
     {
         k=(k+m-1)%i;
         printf("%d\n",t1.head[k]);
        for (j=k;j<i-1; j++)
         {
             t1.head[j] = t1.head[j+1];
         }
         t1.length = t1.length - 1;
    }
    printf("\n");
    printf("幸存者是:");
    printf("%d",t1.head[k]);
}
 
 
int main()
{
    int size;
    printf("请输入总人数:");
    scanf("%d",&size);
    table t1=initTable(size);
    for (int i=1; i<=size; i++) {
     t1.head[i-1]=i;
     t1.length++;
    }
    DisplayList(t1);
}


单链表
	单链表基本操作包括增加、删除、插入、删除、排序、插入,其中插入分为前插和后插。

1.2前插后插子函数:

# include<stdio.h>
#include<stdlib.h>
typedef struct node{
	int num;
    float score;
	struct node *next;
} Lnode;
//前插法
Lnode *Head_Insert(){
	Lnode *ptemp = NULL;
	Lnode *HeadNode = NULL;
	Lnode *p;//前面这里是声明这里有多少个变量
	HeadNode = (Lnode*)malloc(sizeof(Lnode));
	HeadNode->next = NULL;//声明了一个头结点,最后只需要使用这个头结点去发判断序列中是否有元素 
	int x,n,i;
    float y;
    printf("插入数据个数\n"); 
	scanf("%d",&n);
    printf("输入数据\n"); 
	for(i=0;i<n;i++){
        scanf("%d %f",&x,&y);
	ptemp = (Lnode*)malloc(sizeof(Lnode));
		ptemp->num = x;
        ptemp->score=y;
		ptemp->next = NULL; 
		if(HeadNode->next == NULL){
			HeadNode->next = ptemp;	
		} else{
			ptemp->next = HeadNode->next;
			HeadNode->next = ptemp;	
			
		}
		
	} 
	return HeadNode;
}

//尾插法 
Lnode *end_Insert(){
	Lnode *ptemp = NULL;
	Lnode *HeadNode = NULL;
	Lnode *p;
	HeadNode = (Lnode*)malloc(sizeof(Lnode));
	HeadNode->next = NULL;//声明了一个头结点,最后只需要使用这个头结点去发判断序列中是否有元素
	p=HeadNode;  
	int x,n,i;
    float y;
    printf("插入数据个数\n"); 
	scanf("%d",&n);
	printf("输入数据\n"); 
	for(i=0;i<n;i++){
        scanf("%d %f",&x,&y);
	ptemp = (Lnode*)malloc(sizeof(Lnode));
		ptemp->num = x;
        ptemp->score=y;
		ptemp->next = NULL; 
		p->next=ptemp;
		p=ptemp;
		
	} 
	return HeadNode;
}
void printList(Lnode *L){//拿到这个头结点 
	L = L->next;//拿到头结点 
	while(L!=NULL){//判断头结点是否为空 
		printf("%d %2f\n ",L->num,L->score);
		L = L->next;
	}
}
int main(){
	int choice;
	printf("请选择插入方式\n"); 
	printf("1.前插  2.后插\n"); 
	scanf("%d",&choice);
	Lnode *t;
		switch(choice)
		{
			case 1:t =Head_Insert();printList(t);break;
			case 2:t =end_Insert();printList(t);break;
		}
	
	return 0;
}


1.3单链表基本操作代码

#include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    using namespace std;
    #define Status int
    #define ElemType int
    //单链表结点数据结构
    typedef struct LNode
    {
        ElemType data;//数据域
        struct LNode *next;//指针域
    }LNode,*LinkList;
    //**************************基本操作函数***************************//
    //初始化函数
    Status InitList(LinkList &L)
    {
     L = new LNode;//生成头结点 这样删除等操作就不必分第一个结点和其他了
     L->next = NULL;
     return 1;
    }
    //获取单链表长度 头结点无数据,不算
    int ListLength(LinkList L)
    {
        LinkList p=L;int sum=0;
        while(p)
        {
         sum++;
         p=p->next;
        }
        return sum-1;//去除头结点
    }
    //后插 
    bool ListInsert_A(LinkList &L,int i,ElemType e)
    {
        LNode* s;LinkList p=L;int j=0;
        while(p&&(j<i-1))//j指到i-1位置或者p已经到最后时跳出
        {
         p=p->next;
         ++j;
        }
        if(!p||j>i-1)//i<1或者i>ListLength(L)+1时,插入位置无效 不调用ListLength,提高效率
        {
            printf("插入位置无效!!!\n");
            return false;
        }
        s=new LNode;
        s->data=e;
        s->next=p->next;
        p->next=s;
        return true;
    }
    //前插 
	bool ListInsert_B(LinkList &L,int i,ElemType e) 
	{
		LNode* s,* r;LinkList p=L;int j=0;
        while(p&&(j<i-1))//j指到i-1位置或者p已经到最后时跳出
        {
         p=p->next;
         ++j;
        }
        if(!p||j>i-1)//i<1或者i>ListLength(L)+1时,插入位置无效 不调用ListLength,提高效率
        {
            printf("插入位置无效!!!\n");
            return false;
        }
        r=p;
        s=new LNode;
        s->data=e;
        s->next=r->next;
        r->next=s;
	}
    //删除函数 删除位置i的结点 即删除i-1之后的结点
    bool ListDelete(LinkList &L,int i)
    {
         LNode* s;LinkList p=L;int j=0;
        LinkList q;
        while(p&&(j<i-1))//j指到i-1位置
        {
         p=p->next;
         ++j;
        }
        if(!(p->next)||j>i-1)//i<1或者i>ListLength(L)时,删除位置无效
        {
            printf("删除位置无效!!!\n");
            return false;
        }
        q=p->next;
        p->next=q->next;
        free(q);//释放空间
        return true;
    }
    //查找函数 按值查找 查找第一个等于e的结点 成功返回该结点指针,否则返回NULL
    LNode *LocateElem(LinkList L,ElemType e)
    {
        LNode *p=L;
        while(p&&(p->data!=e))
        {
            p=p->next;
        }
        return p;
    }
    //**************************功能实现函数**************************//
    //遍历输出函数
    void PrintList(LinkList L)
    {
        LinkList p=L->next;//跳过头结点
        if(ListLength(L))
        {
            printf("当前单链表所有元素:");
            while(p)
            {
                printf("%d ",p->data);
                p=p->next;
            }
            printf("\n");
        }
        else
        {
            printf("当前单链表已空!\n");
        }
    }
    //插入功能函数 调用ListInsert插入 
    void Insert_A(LinkList &L)
    {
      int place;ElemType e;bool flag;
      printf("请输入要插入的位置(从1开始)及元素:\n");
      scanf("%d%d",&place,&e);
      flag=ListInsert_A(L,place,e);
      if(flag)
      {
        printf("插入成功!!!\n");
        PrintList(L);
      }
    }
    //插入功能函数 调用ListInsert插入 
    void Insert_B(LinkList &L)
    {
      int place;ElemType e;bool flag;
      printf("请输入要插入的位置(从1开始)及元素:\n");
      scanf("%d%d",&place,&e);
      flag=ListInsert_B(L,place,e);
      if(flag)
      {
        printf("插入成功!!!\n");
        PrintList(L);
      }
    }
    //删除功能函数 调用ListDelete删除
    void Delete(LinkList L)
    {
      int place;bool flag;
      printf("请输入要删除的位置(从1开始):\n");
      scanf("%d",&place);
      flag=ListDelete(L,place);
      if(flag)
      {
        printf("删除成功!!!\n");
        PrintList(L);
      }
    }
    //查找功能函数 调用LocateElem查找
    void Search(LinkList L)
    {
      ElemType e;LNode *q;
      printf("请输入要查找的值:\n");
      scanf("%d",&e);
      q=LocateElem(L,e);
      if(q)
      {
        printf("找到该元素!\n");
      }
      else
        printf("未找到该元素!\n");
    }
    //链表最小值 
    LinkList getmin(LinkList L){//取得从指针L开始的链表中记录的最小值
    LinkList min=L;
    while(L->next){
        if((min->data) > (L->next->data)){
            min=L->next;
        }
        L=L->next;
    }
    
    return min;//返回较小值的指针
}
//排序 
void selectsort(LinkList L)//简单选择排序
{
    LinkList j,i=L->next;
    int temp;
    for(;i->next!=NULL;i=i->next){
        j=getmin(i);
        if(i->data!=j->data){
            temp=i->data;
            i->data=j->data;
            j->data=temp;
        }
    }
}

    //菜单
    void menu()
    {
       printf("********1.前插    2.删除*********\n");
       printf("********3.查找    4.输出*********\n");
       printf("********5.后插    6.排序*********\n");
       printf("********7.退出\n"); 
    }
    //主函数
    int main()
    {
     LinkList L;int choice;
     InitList(L);
      menu();
     while(1)
     {
     
      printf("请输入菜单序号:\n");
      scanf("%d",&choice);
      if(choice==7) break;
      switch(choice)
      {
      case 1:Insert_A(L);break;
      case 5:Insert_B(L);break;
      case 2:Delete(L);break;
      case 3:Search(L);break;
      case 4:PrintList(L);break;
      case 6:selectsort(L);PrintList(L);break;
      case 7:break;
      default:printf("输入错误!!!\n");
      }
     }
     return 0;
    }

操作实现
循环链表
循环链表的尾指针指向头结点

1.3约瑟夫环循环链表实现

约瑟夫环问题:有n个人,输入淘汰密码m,报到这个数的人淘汰,再接着从下一个人数接着数,直到最后剩下一个人。
/*
有n个人围城一圈,按顺序编号,从第一个人开始报数,从1报到m,凡报到m的人退出圈子,
然后接着报数,问最后留下来的是原来的第几号的那位?

*/

//循环链表实现
//构造一个循环链表,链表节点的数据域存放人的编号,遍历整个链表,每次报到m的人退出,并释放该节点,直到链表只剩一个节点。
#include <stdio.h>
#include <malloc.h>
 
 /*构建结构体*/
 typedef struct Node{
     int Num;
     struct Node *next;
 }JoseNode, *PNode, *HNode;
 
 /**********初始化循环单链表*********/
 int JoseInit(HNode h)
 {
     if (!h)
     {
         printf("初始化链表错误!\n");
         return 0;
     }
     (h)->next = (h);//循环单链表
     return 1;
 
 }
 
 /*************单链表插入操作**********/
 int JoseInsert(JoseNode *h, int pos, int x)
 {    
     PNode p=h,q;
     int i=1;
     if (pos == 1)/*尾插法*/
     {
         p->Num = x;
         p->next = p;
         return 1;
     }
     while(i<pos-1)
     {
         p=p->next;
         i++;
     }
     q=(PNode)malloc(sizeof(JoseNode));
     q->Num=x;
     q->next=p->next;
     p->next=q;
     return 1;
 }
 
 /*遍历*/
 void TraverseList(HNode h, int M)
 {
     int i = 0;
     PNode p = h;
     printf("参与的人的编号为:\n");
     while (i<M)
     {
         printf("%d\t", p->Num);
         p = p->next;
         i++;
     }
     printf("\n");
 }
 /**************出局函数****************/
 
 int JoseDelete(HNode h, int M, int k)
 {    int i;
     PNode p=h,q;
     while(M>1)
     {
         for(i=1;i<k-1;i++)
         {
             p=p->next;
         }
         
         q=p->next;
         p->next=q->next;
         printf("出局的人为:%d号\n",q->Num);
         free(q);
 
         p=p->next;
         M--;
     }
     printf("***************获胜者为:%d号***************",p->Num);
     return 1;
 }
 
 
 /***************************************/
 int main()
 {
     int i;//计数器
     int N;//参与的人数
     int k;//报数密码
     printf("请输入参与人数:");
     scanf("%d",&N);
     printf("请输入出局密码:");
     scanf("%d",&k);
 
 /**************得到头结点****************/
     HNode h = ((HNode)malloc(sizeof(JoseNode)));
 
 /***************初始化单链表************/
     JoseInit(h);
 
 /******将编号插入到循环单链表中******/
     for (i = 1; i <=N; i++)
     {
         JoseInsert(h, i, i);
     }
 /**************遍历单链表***************/
     TraverseList(h,N);
 
 /***************出局函数************/
     if(k > 1)
     JoseDelete(h, N, k);
     else
     {
         for(i = 1; i < N; i++)
             printf("出局的人为:%d号\n",i);
         printf("***************获胜者为:%d号***************",N);
     }
 
     printf("\n");
     printf("\n");
     return 0;
 }

2.栈和队列

2.1顺序栈的基本操作

顺序栈的操作包括初始化、判空、出栈、入栈、取栈顶元素
#include<stdio.h>
#define MAXSIZE 100

typedef int SELemType;  // SELemType类型根据实际情况而定,这里假设为int
typedef struct
{
    SELemType data[MAXSIZE];
    int top;
}SeqStack;

// 栈初始化
void Init_SeqStack(SeqStack* s)
{
    
    s->top = -1;
}

// 判栈为空
int Empty_SeqStack(SeqStack* s)
{
    if (s->top == -1)
        return 1;
    else
        return 0;
}

// 入栈
void Push_Stack(SeqStack *s, SELemType e)
{
    if (s->top == MAXSIZE - 1)
        printf("Stack is full!\n");
    else
    {
        s->top++;
        s->data[s->top] = e;
    }

}

// 出栈
void Pop_SeqStack(SeqStack* s, SELemType* e)
{
    if (s->top == -1)
        printf("栈为空!\n");
    else
    {
        *e = s->data[s->top];
        s->top--;
    }
}

// 取栈顶元素
void Top_SeqStack(SeqStack* s, SELemType* e)
{
    if (s->top == -1)
        printf("栈为空!\n");
    else
    {
        *e = s->data[s->top];
        printf("出栈成功!\n");
    }
}
// 输出
void Output_SeqStack(SeqStack* s)
{
    SeqStack* w;
    int i;
    printf("栈中的元素有:");
    for (i = s->top; i >= 0; i--)
        printf("%d ", s->data[i]);
    printf("\n");

}
void destroy(SeqStack* s){
	while(s->top!=-1){
	s->top--;}
	printf("已销毁"); 
	
}
void Menu()
{
    puts("****************");
    puts("1.初始化");
    puts("2.判断栈为空");
    puts("3.入栈");
    puts("4.出栈");
    puts("5.得到栈顶元素");
    puts("6.销毁");
    puts("0.程序结束");
    puts("****************");

}

// 主函数
int main()
{
    SeqStack S;
    int choice = -1, i,n;
    SELemType e;
    Menu();
    while (choice == -1)
    {
        printf("\nYour choice is:");
        scanf("%d", &i);
        switch (i)
        {
        case 1:
            Init_SeqStack(&S);
            printf("初始化完成!\n");
            break;
        case 2:
            if(Empty_SeqStack(&S) == 1)
                printf("栈为空!\n");
            else
                printf("栈不为空!\n");
            break;
        case 3:
            printf("请输入入栈的数量:");
            scanf("%d", &n);
            printf("请输入需要入栈的数据,用空格隔开:");
            for (int j = 0; j < n; j++)
            {
                scanf("%d", &e);
                Push_Stack(&S, e);
            }
            Output_SeqStack(&S);
            break;;
        case 4:
            Pop_SeqStack(&S, &e);
            Output_SeqStack(&S);
            break;
        case 5:
            Top_SeqStack(&S, &e);
            printf("栈顶元素为:%d\n", e);
            Output_SeqStack(&S);
            break;
        case 6:destroy(&S);break;
        case 0:
            choice = 0;
            break;
        default:printf("选择有误,请重新选择 \n");
        }
    }
    puts("\n");
    puts("\t\t\t\t  By Cherish599");
    return 0;
}

栈基本操作

2.2迷宫的栈实现

给一个二维列表,表示迷宫(0表示通道,1表示围墙)。给出算法,求一条走出迷宫的路径。

include <iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;

//定义一个迷宫,0为可通的路,
//1表示不可前进的路,并且给迷宫加上了边框,所以在周围会有一圈1
const int M = 8, N = 8;
const int maxSize = 1e4 + 10;

int mg[M + 2][N + 2] = {
	{1,1,1,1,1,1,1,1,1,1},
    {1,0,0,1,0,0,0,1,0,1},
    {1,0,0,1,0,0,0,1,0,1},
    {1,0,0,0,0,1,1,0,0,1},
    {1,0,1,1,1,0,0,0,0,1},
    {1,0,0,0,1,0,0,0,0,1},
    {1,0,1,0,0,0,1,0,0,1},
    {1,0,1,1,1,0,1,1,0,1},
    {1,1,0,0,0,0,0,0,0,1},
    {1,1,1,1,1,1,1,1,1,1}
};

//定义一个结构体,该结构体表示迷宫每个元素的坐标以及方位数。
struct Box {
	int i;
	int j;
	int di;
};

//定义一个迷宫栈,下面包括迷宫栈的一系列的函数
struct SNode {
	Box Data[maxSize];
	int top;
};
typedef SNode* Stack;

void Init(Stack& S)
{
	S = new SNode;
	S->top = -1;
}

bool Push(Stack& S, Box e)
{
	if (S->top == maxSize - 1)
		return false;
	S->top++;
	S->Data[S->top] = e;
	return true;
}

bool Pop(Stack& S, Box& e)
{
	if (S->top == -1)
		return false;
	e = S->Data[S->top];
	S->top--;
	return true;
}

bool GetTop(Stack S, Box& e)
{
	if (S->top == -1)
		return false;
	e = S->Data[S->top];
	return true;
}

bool Empty(Stack S)
{
	return (S->top == -1);

}

void destroy(Stack& S)
{
	free(S);
}

//该算法即为迷宫的算法
bool solve(int xi, int yi, int xe, int ye)
{
	Box e,path[maxSize];
	int i, j, di, i1, j1,k;
	Stack S;
	Init(S);
	bool find;

	e.i = xi; e.j = yi; e.di = -1;
	Push(S, e);
	mg[xi][yi] = -1;
	while (!Empty(S))
	{
		GetTop(S, e);
		i = e.i; j = e.j; di = e.di;
		if (i == xe && j == ye)
		{
			cout << "恭喜你找到了一条迷宫的路径!" << endl;
			k = 0;
			while (!Empty(S))
			{
				Pop(S, e);
				path[k++] = e;
			}
			while (k >= 1)
			{
				k--;
				cout << '(' << path[k].i << ',' << path[k].j << ')' << "	";
				if ((k + 2) % 5 == 0)
				{
					cout << endl;
				}
			}
			destroy(S);
			return true;
		}
		
		find = false;
		while (di < 4 && !find)
		{
			di++;
			switch (di)
			{
			case 0:
				i1 = i - 1; j1 = j; break;
			case 1:
				i1 = i; j1 = j + 1; break;
			case 2:
				i1 = i + 1; j1 = j; break;
			case 3:
				i1 = i; j1 = j - 1; break;
			}
			if (mg[i1][j1] == 0)
				find = true;
		}
		if (find)
		{
			S->Data[S->top].di = di;
			mg[i][j] = -1;
			e.i = i1; e.j = j1; e.di = -1;
			Push(S, e);
		}
		else
		{
			Pop(S, e);
			mg[i][j] = 0;
		}
	}
	destroy(S);
	return false;
}

int main()
{
	solve(1, 1, 8, 8);
}

在这里插入图片描述

2.3队列顺序表实现

基本操作包括初始化、入队、出队、求队长
#include<stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
typedef struct sequence
{
	int quence[MAXSIZE];
	int front;				//队头 
	int rear;				//队尾 
}Sequence;
void Init(Sequence *S)
{
	S->front =S->rear =0; 
}
int Length(Sequence S)
{
return (S.rear-S.front+MAXSIZE)%MAXSIZE;      
}
int In(Sequence *S,int e)
{
	if(S->rear>=MAXSIZE)
	{
		printf("队满"); 
		return 0;
	}
	S->quence[S->rear]=e;
	S->rear =(S->rear+1)%MAXSIZE;				//这行代码就是防止溢出,向后遍历
	return 1;
}
int Out(Sequence *S)
{
	if(S->front==S->rear)
	return 0;
	printf("\n%d\n",S->quence[S->front]);
	S->front =(S->front+1)%MAXSIZE;
	return 1;	
}
int Print(Sequence S)
{
	int i;
	i=S.front;
	while(i!=S.rear)
	{
		printf("%d\t",S.quence[i]);
		i = (i+1)%MAXSIZE;
	}
	return 1;
}
int main()
{
	Sequence s;
	int i,date,n;
	printf("1,初始化\n2,入队创建\n3,入队\n4,出队\n5,打印\n6,队-长\n0,退出\n");
	printf("输入操作:"); 
	scanf("%d",&n);
	while(n!=0) 
	{
		switch(n)
		{
			case 1:
				Init(&s);
				printf("初始化完成\n");
				break;
			case 2:
				printf("length:");
				scanf("%d",&n);
				printf("输出整形数据:\n");
				for(i=0;i<n;i++)
				{
					scanf("%d",&date);
					In(&s,date);
				} 
				printf("创建完成!\n");
				break;
			case 3:
				printf("输入入队数据:");
				scanf("%d",&date);
				In(&s,date);
				printf("入队完成!\n");
				break;
			case 4:
				printf("出队");
				Out(&s);
				printf("完成!\n");
				break;
			case 5:
				printf("打印\n");
				Print(s);
				printf("打印完成!\n");
				break;
			case 6:
				printf("队-长:%d\n",Length(s));
				break;
		}
		printf("————输入操作:"); 
		scanf("%d",&n);
	}
	return 0;
}


2.4队列链表实现

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
// 队列的节点 
struct Node
{
        int data;
        struct Node* next;
};
// 队首队尾指针 
struct Queue
{
        struct Node* front;
        struct Node* rear;
        int size;
};
 //初始化 
void QueueInit(struct Queue* queue)
{
        queue->front = NULL;
        queue->rear = NULL;
        queue->size = 0;
}
 //判断是否为空 
int QueueEmpty(struct Queue* queue)
{
        return (queue->size == 0);
}
 //入队 
void QueuePush(struct Queue* queue, const int data)
{
        struct Node* node;
        node = (struct Node*)malloc(sizeof(struct Node));
        assert(node != NULL);
        
        node->data = data;
        node->next = NULL;
        
        if(QueueEmpty(queue))//若为空
        {
            queue->front = node;
            queue->rear = node;
        }
        else//若不为空 
        {            
            queue->rear->next = node;
            queue->rear = node;
        }
        ++queue->size;
}
//长度 
int Queuelen(struct Queue* queue){
	int sum=0;
	struct Node* tmp = queue->front;
	while(tmp){
		sum++;tmp=tmp->next;
	}
	return sum;
}
//遍历 
void Queuetrav(struct Queue* queue){
		struct Node* tmp = queue->front;
 		while(tmp){
 		printf(" %d",tmp->data);
 		tmp= tmp->next;
 		}
 	}
//头元素 
void QueueH(struct Queue* queue){
	printf("%d",queue->front->data);
}
 //出队 
int QueuePop(struct Queue* queue, int* data)
{
        if (QueueEmpty(queue))
        {
                return 0;
        }
        struct Node* tmp = queue->front;
        *data = queue->front->data;
        queue->front = queue->front->next;
        free(tmp);
        --queue->size;
 
        return 1;
}
 //销毁 
void QueueDestroy(struct Queue* queue)
{
     struct Node* tmp;
     while(queue->front)
     {
         tmp = queue->front;
         queue->front = queue->front->next;
         free(tmp);
     }
}
 
int main(void)
{
		int n,e,m;
        struct Queue queue;
        QueueInit(&queue);
        printf("请输入入队的数量:");
        scanf("%d", &n);
        printf("请输入需要入队的数据,用空格隔开:");
        for (int j = 0; j < n; j++)
        {
            scanf("%d", &e);
            QueuePush(&queue,e);
        }
        
        Queuetrav(&queue);
        printf("\n");
        printf("长度\n");
        m=Queuelen(&queue);
        printf("%d",m);printf("\n");
        printf("头元素");
        QueueH(&queue);
        printf("\n");
        printf("出队");
        while (!QueueEmpty(&queue))
        {
                QueuePop(&queue, &e);
                printf("%d ",e);
        }
 
        printf("\n");
 
        return 0;
}

2.5迷宫求解队列实现

给一个二维列表,表示迷宫(0表示通道,1表示围墙)。给出算法,求一条走出迷宫的路径。

#include<stdio.h>
#define MaxSize 100
#define M 8
#define N 8
typedef struct
{   int i,j;    //方块在迷宫中的坐标位置(i,j)         
    int pre;    //本路径中上一方块在队列中的下标   
} SqQueue; 
SqQueue Qu[MaxSize];  //定义顺序非循环队列
int front=0,rear=0; 
int mg[M+2][N+2]=
{
    {1,1,1,1,1,1,1,1,1,1},
    {1,0,0,1,0,0,0,1,0,1},
    {1,0,0,1,0,0,0,1,0,1},
    {1,0,0,0,0,1,1,0,0,1},
    {1,0,1,1,1,0,0,0,0,1},
    {1,0,0,0,1,0,0,0,0,1},
    {1,0,1,0,0,0,1,0,0,1},
    {1,0,1,1,1,0,1,1,0,1},
    {1,1,0,0,0,0,0,0,0,1},
    {1,1,1,1,1,1,1,1,1,1}
};
void print(SqQueue Qu[],int front)
{   int k=0;
    for(int i=front;i>0;i=Qu[i].pre)
    {
        printf("(%d,%d) ",Qu[i].i,Qu[i].j);
        k++;
        if(k%5==0)   //每输出每5个方块后换一行
           printf("\n");
    }
}
bool mgpath1(int xi,int yi,int xe,int ye)	//搜索路径为:(xi,yi)->(xe,ye)
{   int i, j, di, i1, j1;
    rear++;
    Qu[rear].i=xi; Qu[rear].j=yi; Qu[rear].pre=-1; //(xi,yi)进队
    mg[xi][yi]=-1;		        //将其赋值-1,以避免回过来重复搜索
    while(front!=rear)		    //队不空循环
    {   front++;
        i=Qu[front].i; j=Qu[front].j; //出队
        if (i==xe && j==ye)	    //找到了出口,输出路径
        {   print(Qu, front);	//调用print函数输出路径
            return true;		//找到一条路径时返回真
        }
        for (di=0;di<4;di++)    //循环扫描每个方位
        {	
          switch(di)
          {
            case 0:i1=i-1;   j1=j; break;
            case 1:i1=i;  j1=j+1; break;
            case 2:i1=i+1;  j1=j; break;
            case 3:i1=i;   j1=j-1; break;
          }
          if (mg[i1][j1]==0)
          {   rear++;
              Qu[rear].i=i1; Qu[rear].j=j1; 
              Qu[rear].pre=front;	//(i1,j1)方块进队
              mg[i1][j1]=-1;	//将其赋值-1
          }
        }//for
    }//while
    return false;
}//mgpath1
 
int main()
{ 
    if (!mgpath1(8,8,1,1))
        printf("该迷宫问题没有解!");
    return 1;
}

3.字符串和数组

3.1BF与KMP代码

字符串的模式匹配:在主串S中查找与模式T相匹配的子串,如果匹配成功,确定相匹配的子串的第一个字符在主串中出现的位置
著名的模式匹配算法有BF算法、KMP算法。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 100

//串结构体
typedef struct Stirngs
{
	char string[100];
	int length;
}SString;


//next数组
void get_next(SString T, int next[])
{
	int i = 0,j = -1;//下标从0开始 
	next[0] = -1;
	while (i < T.length)
	{
		if (j == -1 || T.string[i] == T.string[j]){i++;j++;next[i] = j;}
		else
			j = next[j];
	}
	
}
 //KMP算法
	int Index_KMP(SString S,SString T,int next[])
	{
		int i = 0,sum=0;
		int j = 0;
		while (i < S.length && j <T.length)       //合法长度之内
		{
			if(j== -1||S.string[i]==T.string[j]) {i++;j++;sum++;}
			else
				{j = next[j];sum++;}                  //利用Next数组进行移动

		}

		if (j ==T.length)
			return sum;
		else
			return -1;
	}
//BF算法 
int Index_BF(SString S,SString T,int pos){
	int i=pos,j=0,sum=0;
	while (i < S.length && j <T.length)       //合法长度之内
		{
			if(	S.string[i]==T.string[j]) {++i;++j;sum++;}
			else
				{i=i-j+1;j=0;sum++; } 
			}                   
	if(j==T.length) return sum;
	else
		return -1;

}
	/*主函数*/
	int main(void)
	{
		int next[N],choice;
		SString S,T ;
		printf("Please Input S string: \n");
		scanf("%s", S.string);
		printf("Please Input T string: \n");
		scanf("%s", T.string);
		S.length = strlen(S.string);
		T.length = strlen(T.string);
		printf("请输入菜单序号:1:KMP  2:BF\n");
        scanf("%d",&choice);
        switch(choice)
      	{
      		case 1:get_next(T,next);printf("KMP 算法的子串比较次数为%d",Index_KMP(S,T,next));break;
      		case 2:printf("BF 算法的子串比较次数为%d",Index_BF(S,T,0));break;
      		default:printf("输入错误!!!\n");
      	}
		printf("\n");
		
	}

3.2 经典KMP算法判断

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 100

/*串结构体*/
typedef struct Stirngs
{
	char string[100];
	int length;
}SString;


/*next数组*/
void get_next(SString T, int next[])
{
	int i = 0,j = -1;//下标从0开始 
	next[0] = -1;
	while (i < T.length)
	{
		if (j == -1 || T.string[i] == T.string[j]){i++;j++;next[i] = j;}
		else
			j = next[j];
	}
	

}
 /*KMP算法*/
	int Index_KMP(SString S,SString T,int next[])
	{
		int i = 0;
		int j = 0;
		while (i < S.length && j <T.length)       //合法长度之内
		{
			if(j== -1||S.string[i]==T.string[j]) {i++;j++;}
			else
				j = next[j];                     //利用Next数组进行移动

		}
		
		if (j ==T.length)
			return i - T.length+1;
		else
			return -1;
	}

	/*主函数*/
	int main(void)
	{
		int next[N];
		int a;
		SString S ;
		SString T ;
		printf("Please Input S string: \n");
		scanf("%s", S.string);
		printf("Please Input T string: \n");
		scanf("%s", T.string);
		S.length = strlen(S.string);
		T.length = strlen(T.string);
		get_next(T,next);
		printf("\n");
		if (Index_KMP(S, T, next)!= -1)
		{
			printf("在主串位置:%d",Index_KMP(S, T, next));
			
		}
		else
			printf("-1");

		printf("\n");
		system("pause");
		return 0;
	}


3.3 字符串匹配

给定两个字符串string1和string2,判断string2是否为string1的子串。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 100

/*串结构体*/
typedef struct Stirngs
{
	char string[100];
	int length;
}SString;


/*next数组*/
void get_next(SString T, int next[])
{
	int i = 0,j = -1;//下标从0开始 
	next[0] = -1;
	while (i < T.length)
	{
		if (j == -1 || T.string[i] == T.string[j]){i++;j++;next[i] = j;}
		else
			j = next[j];
	}
	

}
 /*KMP算法*/
	int Index_KMP(SString S,SString T,int next[])
	{
		int i = 0;
		int j = 0;
		while (i < S.length && j <T.length)       //合法长度之内
		{
			if(j== -1||S.string[i]==T.string[j]) {i++;j++;}
			else
				j = next[j];                     //利用Next数组进行移动

		}
		
		if (j ==T.length)
			return i - T.length+1;
		else
			return -1;
	}

	/*主函数*/
	int main(void)
	{
		int next[N];
		int a;
		SString S ;
		SString T ;
		printf("Please Input S string: \n");
		scanf("%s", S.string);
		printf("Please Input T string: \n");
		scanf("%s", T.string);
		S.length = strlen(S.string);
		T.length = strlen(T.string);
		get_next(T,next);
		printf("\n");
		if (Index_KMP(S, T, next)!= -1)
		{
			printf("YES\n");
			
		}
		else
			printf("NO");

		printf("\n");
		system("pause");
		return 0;
	}

3.4字符串1匹配2

有n个同学,每个同学手里有一些糖块,现在这些同学排成一排,编号是由1到n。现在给出m个数,能不能唯一的确定一对值l和r(l <= r),使得这m个数刚好是第l个同学到第r个同学手里的糖块数?
首先输入一个整数n,代表有n个同学。下一行输入n个数,分别代表每个同学手里糖的数量。
之后再输入一个整数m,代表下面有m个数。下一行输入这m个数。如果能唯一的确定一对l,r的值,那么输出这两个值,否则输出-1
样例

include<bits/stdc++.h>
using namespace std;
int next[1000000];
int get_next(char s[])
{
    int len=strlen(s);
    int i=0,j=-1;
    next[0]=-1;
    while(i<len)   //i<len
    {
        if(j==-1||s[i]==s[j])
        {
            i++;j++;
           if(s[i]!=s[j]) next[i]=j;
            else
            next[i]=next[j];
        }
        else
            j=next[j];
    }
}
int index_kmp(char s[],char c[])
{
    get_next(c);
    int len=strlen(s);
    int len1=strlen(c);
    int i=0,j=0,ans=0;
    int flag=-1;  //标记第一取得配对的串的下标
    while(i<len)
    {
        if(j==-1||s[i]==c[j])
        {
            i++;j++;
        }
        else
            j=next[j];
        if(j>=len1)       //统计子串在母串中的个数,可重叠 ababa  aba 2
        {
            ans++;
            j=next[j];
            //j=0 ;    //统计子串在母串中的个数,不重叠ababa aba 1
		
            if(flag==-1)      //记录第一次配对成功的下标值,否则i会持续变大到最后
				flag=i;
        }
    }
    if(ans!=1)
  return -1;
   else
	return flag-len1+1;
}
char s[10000000],c[10000000];   
int main()
{
	char s1[10];
	int n,m;
	scanf("%d",&n); 
	for(int i=0;i<n;i++)
	{	scanf("%s",s1);
		s[i]=s1[0];
	}
	scanf("%d",&m);
	for(int i=0;i<m;i++)
	{
		scanf("%s",s1);
		c[i]=s1[0];
	}
	s[n]='\0';c[m]='\0';
		//printf("%s*%s*",s,c);
	int flag=index_kmp(s,c);//Getkmp(s,s1,n,m);
	if(flag!=-1)
		printf("%d %d\n",flag,flag+m-1);
	else
		printf("-1\n");
	
	return 0;
}

数组

3.5蛇形填数1

在这里插入图片描述

#include<stdio.h>
#define MAX 100
int a[MAX][MAX]={0};//将整个数组初始化为零
int main()
{
	int i=0,j=0;
	int n,count=1;
	scanf("%d",&n);
	if(n>MAX)//如果输入的数组大于初始化的数组,程序结束
		return 0;
	j=n-1;
	while(count<=n*n)//这点需要注意 必须是小于等于 
	{                //如果输入的数是偶数的话小于就够了 但当输入的数是奇数就需要等于才行
		while(i<n && !a[i][j])//!a[i][j]这也是必须加的 先从最右边填
		{
			a[i][j]=count++;
			i++;
		}
		while(j>0 && !a[i-1][j-1])
		{
			a[i-1][j-1]=count++;
			j--;
		}
		while(i>1 && !a[i-2][j])
		{
			a[i-2][j]=count++;
			i--;
		}
		while(j<n-2 && !a[i-1][j+1])
		{
			a[i-1][j+1]=count++;
			j++;
		}
	}
	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)
		{
			printf("%3d",a[i][j]);
		}
		printf("\n");
	}	
	return 0;
}

3.6蛇形填数2

在这里插入图片描述

#include<stdio.h>
#include<string.h>
#define maxn 1100
int a[maxn][maxn];
int main()
{
	int x,y,n,tot;
	memset(a,0,sizeof(a));
	scanf("%d",&n);
	tot=a[x=0][y=0]=1;
	while(tot<n*(n+1)/2)
	{
		while(y+1<n && !a[x][y+1]) a[x][++y]=++tot;
		while(x+1<n && y-1>=0 && !a[x+1][y-1]) a[++x][--y]=++tot;
		while(x-1>=0 && !a[x-1][y]) a[--x][y]=++tot;
	}
	for(x=0;x<n;x++)
	{
		for(y=0;y<n;y++)
		{
			if(a[x][y])
				printf("%4d ",a[x][y]);
		}		
			printf("\n");
	}
}

3.7蛇形填数3

在这里插入图片描述

#include <stdio.h>
int main()
{
    int m=0,i=0,j=0,c=1,n;
    scanf("%d",&n);
    int a[n][n];
    while(c<=n*n){
        while(m<n){
            for(i=m,j=0;i>=0,j<=m;i--,j++){
                
                 a[i][j]=c++;
                 
            }
            m++;
        }
        m=1;
       while(m<n){
           for(i=n-1,j=m;i>=m,j<=n-1;i--,j++){
               a[i][j]=c++;
           }
           m++;
       }
    }
    for(i=0;i<n;i++){
        for(j=0;j<n;j++){
            printf("%d  ",a[i][j]);
        }
        printf("\n");
    }
    
}

3.8 递归与非递归

斐波那契数列和n的阶乘

#include<stdio.h>
#include <stdlib.h>
#include <string.h> 
int a[1005][1005];
//斐波那契递归函数(大数) 
void fibD(int n){
	int c;
		int d=0;
		memset(a,0,sizeof(a));//初始化 
		a[1][0]=1;a[2][0]=1;//第一个和第二个数要先保存下来 
		for(int i=3;i<=n;i++)//从第三个数开始都是等于前两个数的和 
		{
			c=0;//保存余数 
			for(int j=0;j<=d;j++)
			{
		    	a[i][j]=a[i-1][j]+a[i-2][j]+c;//计算结果 
				c=a[i][j]/10;//将其他的数进位 
				a[i][j]%=10;//将大于10的数要余数 
			}
			while(c!=0)//最后一位要是大于10,需要进位,并且最高位也需要加1! 
			{
				a[i][++d]=c%10;c/=10;
			}
		}
		for(int i=d;i>=0;i--) {
		printf("%d",a[n][i]);
		}
		printf("\n");
}
//斐波那契非递归 
long int Fib(int n){
	long int f1=1,f2=1,f3;
	if(n==1||n==2) return 1;
	for( int i=3;i<=n;i++){
		f3=f2+f1;f1=f2;f2=f3;
	}
	return f3;	
}
//阶乘递归函数 
long int Fact(int n){
	if(n==0||n==1)return 1;
	else return n*Fact(n-1);
}
//阶乘非递归函数 
long int fact(int n){
	if(n==1||n==0){return 1;}
	long long int m=1;
	for(int i=1;i<=n;i++){
		m*=i;
	}
	return m;
}
int main(){
	int n,choice;
	printf("1. 递归求斐波那契\n"); 
    printf("2. 非递归求斐波那契\n"); 
    printf("3. 递归求阶乘\n"); 
    printf("4. 非递归求阶乘\n");  
    printf("5. 退出\n"); 
    printf("请选择(1-5):"); 
    scanf("%d",&choice); 
    printf("输入要计算的数字:\n");
	scanf("%d",&n);
	switch(choice){
		case 1:fibD(n);break;
		case 2:printf("%ld",Fib(n));break;
		case 3:printf("%ld",fact(n));break;
		case 4:printf("%ld",Fact(n));break;
		case 5:exit(0);break;
	}
	return 0;
}

3.9回文数判断

输入一个数据,如果是回文数则输出“是回文数”

#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void Palindrome(char * arr1, char *arr2)
{
	int i, len, mid, next, top;
	printf("请输入:\n");
	gets(arr1);
	len = strlen(arr1);
	mid = len / 2 - 1;
	top = 0;
	for (i = 0; i <= mid; i++) //前半部分倒序存 
	{
		arr2[++top] = arr1[i];
	}
 
	if (len%2 == 0)
	{
		next = mid + 1;
	}
	else
	{
		next = mid + 2;
	}
	for (i = next; i <= len - 1; i++)
	{
		if (arr1[i] != arr2[top])
		{
			break;
		}
		top--;
	}
 
	if (top == 0)
	{
		printf("%s是回文数!\n",arr1);
	}
	else
	{
		printf("%s不是回文数\n", arr1);
	}
}
int main()
{
	char arr1[101];
	char arr2[101];
	Palindrome(arr1, arr2);
	system("pause");
	return 0;
}

3.10任意进制转换

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
long  toTen(char a[], int bit)
//转为十进制(多项式求和 )sum=a[i]*该位位权 求和,i从len-1到0
{
    int length = strlen(a);
    int i, b=1,sum=0; 
    for(i=length-1;i>=0;i-- )
    {
        if(a[i]>='A') 
        {
            sum += (a[i]-'A'+10) *b;
            b *= bit;
        }
        else           
        {
            sum += (a[i]-'0') *b;
            b *= bit;
        }
    }
    return sum;
}
 
void tentoN(long int tenn,int m){
	//十进制转换成其他进制(取余法,余数倒排即为结果) 
    int r[500];
    int j=0;
    int shang=tenn;
    while(shang!=0){
        r[j++]=shang%m;
        shang=shang/m;
    }
    for(int i=j-1;i>=0;i--){ 
        if(r[i]>=10){
            printf("%c",r[i]-10+'A');
        }else{
            printf("%d",r[i]);
        }
    }
}
 
int main()
{
    int n;
    char a[500];
    char renyi[500];
    int m;
    long int tenn;
    printf("输入原进制、要转换的数、转换后的进制:\n");
    scanf("%d %s %d",&n,a,&m);
    tenn=toTen(a,n);
    tentoN(tenn,m);
    return 0;
}

4.树和二叉树

4.1二叉树递归遍历

用递归实现二叉树的先序、 中序、 后序 3 种遍历。
测试输入样例 FCA##DB###EH##GM###

#include<stdio.h>
#include<stdlib.h>
typedef struct BiTNode{
	char data;
	struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
BiTree CreateBiTree(){
	BiTree T;
	char c;
	scanf("%c",&c);
	if('#'==c){
		T=NULL;
	}
	else{
	
		T=(BiTree)malloc(sizeof(BiTNode));
		T->data=c;
		T->lchild=CreateBiTree( );
		T->rchild=CreateBiTree( );
		}
		return T;
}
void visit(char data){
	printf("%c\n",data);
}
void PreOrderTrverse(BiTree T){
	if(T){
		visit(T->data);
		PreOrderTrverse(T->lchild);
		PreOrderTrverse(T->rchild);
	}
}
void InOrderTrverse(BiTree T){
	if(T){
		
		InOrderTrverse(T->lchild);
		visit(T->data);
		InOrderTrverse(T->rchild);
	}
}
//后序遍历 
void PostOrderTrverse(BiTree T){
	if(T){
		
		PostOrderTrverse(T->lchild);
		PostOrderTrverse(T->rchild);
		visit(T->data);
	}
}
//树的深度 
int Depth(BiTree T){
	int m,n;
	if(T==NULL) return 0;
	else{
		m=Depth(T->lchild);
		n=Depth(T->rchild);
		if(m>n) return(m+1);
		else return(n+1);
	}
}
int main(){
	BiTree T;
	T=CreateBiTree();
	printf("先序遍历\n");
	PreOrderTrverse(T);
	printf("中序遍历\n");
	InOrderTrverse(T);
	printf("后序遍历\n");
	PostOrderTrverse(T);
	printf("%d",Depth(T));
	return 0;
}
//FCA##DB###EH##GM###

4.2二叉树非递归遍历

测试输入样例 FCA##DB###EH##GM###

#include <stdio.h>
#include <stdlib.h> 
#define MAXSIZE 200
 
/* 定义二叉树节点类型 */
typedef struct BiTNode
{
    char data;
    struct BiTNode *lchild, *rchild;
}BiTNode;
 
/* 函数声明 */
BiTNode* CreatBitTree();
void PreOrder(BiTNode*);
void InOrder(BiTNode*);
void PostOrder(BiTNode*);
 
/* 主函数 */
int main()
{
    BiTNode *root = NULL;
    root = CreatBitTree();
    printf("先序\n");
    PreOrder(root);
    printf("中序\n");
    InOrder(root);
    printf("后序\n");
    PostOrder(root);
    system("pause");
    return 0;
}
 
/* 递归前序建立二叉树 */
BiTNode* CreatBitTree()
{
    char ch;
    BiTNode *b;
    scanf("%c", &ch);
    /* 遇到空节点停止递归 */
    if (ch == '#')
    {
        b = NULL;
    }
    else
    {
        b = (BiTNode*) malloc(sizeof(BiTNode));
        /* 建立根节点 */
        b->data = ch;
        /* 递归先序建立左子树 */
        b->lchild = CreatBitTree();
        /* 递归先序建立右子树 */
        b->rchild = CreatBitTree();
    }
    return b;
}
 
/* 非递归前序遍历二叉树 */
void PreOrder(BiTNode* b)
{
    BiTNode *stack[MAXSIZE], *p;
    int top = -1;
    if (b != NULL)
    {
        /* 根节点入栈 */
        top++;
        stack[top] = b;
        /* 栈不空时循环 */
        while (top > -1)
        {
            /* 出栈并访问该节点 */
            p = stack[top];
            top--;
            printf("%c ", p->data);
            /* 右孩子入栈 */
            if (p->rchild != NULL)
            {
                top++;
                stack[top] = p->rchild;
            }
            /* 左孩子入栈 */
            if (p->lchild != NULL)
            {
                top++;
                stack[top] = p->lchild;
            }
        }
        printf("\n");
    }
}
 
/* 非递归中序遍历二叉树 */
void InOrder(BiTNode* b)
{
    BiTNode *stack[MAXSIZE], *p;
    int top = -1;
    if (b != NULL)
    {
        p = b;
        while (top > -1 || p != NULL)
        {
            /* 扫描p的所有左节点并入栈 */
            while (p != NULL)
            {
                top++;
                stack[top] = p;
                p = p->lchild;
            }
            if (top > -1)
            {
                /* 出栈并访问该节点 */
                p = stack[top];
                top--;
                printf("%c ", p->data);
                /* 扫描p的右孩子 */
                p = p->rchild;
            }
        }
        printf("\n");
    }
}
 
/* 非递归后序遍历二叉树 */
void PostOrder(BiTNode* b)
{
    BiTNode *stack[MAXSIZE], *p;
    int sign, top = -1;
    if (b != NULL)
    {
        do
        {
            /* b所有左节点入栈 */
            while (b != NULL)
            {
                top++;
                stack[top] = b;
                b = b->lchild;
            }
            /* p指向栈顶前一个已访问节点 */
            p = NULL;
            /* 置b为已访问 */
            sign = 1;
            while (top != -1 && sign)
            {
                /* 取出栈顶节点 */
                b = stack[top];
                /* 右孩子不存在或右孩子已访问则访问b */
                if (b->rchild == p)
                {
                    printf("%c ", b->data);
                    top--;
                    /* p指向被访问的节点 */
                    p = b;
                }
                else
                {
                    /* b指向右孩子节点 */
                    b = b->rchild;
                    /* 置未访问标记 */
                    sign = 0;
                }
            }
        }while (top != -1);
        printf("\n");
    }

}
//FCA##DB###EH##GM###


4.3二叉树层次遍历

层次遍历:从上到下、从左到右

#include <stdio.h>
#include <stdlib.h>
 
//二叉链表类型定义
typedef struct BTNode
{
char data;
struct BTNode *lchild,*rchild;
}BiTree,*Bitree;


//链队列类型定义
typedef struct LinkQueueNode
{
BiTree *data;
struct LinkQueueNode *next;
}LKQueNode;


typedef struct LKQueue
{
LKQueNode *front,*rear;
}LKQue;


//初始化队列
void InitQueue(LKQue *LQ)
{
LKQueNode *p;
p = (LKQueNode*)malloc(sizeof(LKQueNode));
LQ->front = p;
LQ->rear = p;
LQ->front->next = NULL;
}


//判断队列是否为空
int EmptyQueue(LKQue *LQ)
{
if(LQ->front == LQ->rear)
return 1;
else 
return 0;
}


//入队列
void EnQueue(LKQue *LQ,Bitree x)
{
LKQueNode *p;
p = (LKQueNode*)malloc(sizeof(LKQueNode));
p->data = x;
p->next = NULL;
LQ->rear->next = p;
LQ->rear = p;
}


//出队列
int OutQueue(LKQue *LQ)
{
LKQueNode *s;
if ( EmptyQueue(LQ))
{
exit(0);
return 0;
}
else
{
s = LQ->front->next;
LQ->front->next = s->next;
if(s->next == NULL)
LQ->rear = LQ->front;
free(s);
return 1;
}
}


//取队列首元素
Bitree GetHead(LKQue *LQ)
{
LKQueNode *p;
BiTree *q;
if(EmptyQueue(LQ))
return q;
else 
{
p = LQ->front->next;
return p->data;
}
} 


//建二叉树
Bitree Initiate()
{
char ch;
Bitree t;
ch = getchar();    
if(ch == '#') 
t = NULL;
   else
   {
t = (Bitree)malloc(sizeof(BiTree));
t->data = ch;
t->lchild = Initiate();
t->rchild = Initiate();
   }
   return t;
}


//访问节点
void Visit(Bitree p)
{
printf("%c",p->data); //输出是char
}


//树的高度
int height(Bitree t)
{
int ld,rd;
if(t == NULL) 
return 0;
else 
{
ld = height(t->lchild);
rd = height(t->rchild);
return 1 + (ld>rd?ld:rd);
}
}
 
//层次遍历 
void LevelOrder(Bitree bt)
{
LKQue Q;
Bitree p;
InitQueue(&Q);
if(bt != NULL)
{
EnQueue(&Q,bt);
while(!EmptyQueue(&Q))
{
p = GetHead(&Q);
OutQueue(&Q);
Visit(p);
if(p->lchild != NULL)  
EnQueue(&Q,p->lchild);
if(p->rchild != NULL)  
EnQueue(&Q,p->rchild);
}
}
}


int main()
{
Bitree T;
//printf("\n按先序序列输入结点序列,'#'代表空:");
T=Initiate();


//printf("\n二叉树的高度为:%d\n",height(T));


printf("\n层次遍历序列为:");
LevelOrder(T);


printf("\n\n");
return 0;
}

4.4交换左右子树

把二叉树的所有左右子树进行交换

include<stdio.h>
#include<stdlib.h>
typedef struct BiTNode{
	char data;
	struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
BiTree CreateBiTree(){
	BiTree T;
	char c;
	scanf("%c",&c);
	if('#'==c){
		T=NULL;
	}
	else{
	
		T=(BiTree)malloc(sizeof(BiTNode));
		T->data=c;
		T->lchild=CreateBiTree( );
		T->rchild=CreateBiTree( );
		}
		return T;
}
void visit(char data){
	printf("%c\n",data);
}
//交换左右二叉树;先序 
void Exchange(BiTree T)
{
	if(T->lchild==NULL&&T->rchild==NULL)
		;
	else    
	{
		
		BiTree temp=T->lchild;
		T->lchild=T->rchild;
		T->rchild=temp;
		if(T->lchild) 	  		
			Exchange(T->lchild);
		if(T->rchild)
			Exchange(T->rchild);
	}
}
void PreOrderTrverse(BiTree T){
	if(T){
		visit(T->data);
		PreOrderTrverse(T->lchild);
		PreOrderTrverse(T->rchild);
	}
}
int main(){
	BiTree T;
	T=CreateBiTree();
	Exchange(T);
	printf("先序遍历\n");
	PreOrderTrverse(T);
	
	return 0;
}

4.5二叉树深度

树的深度:结点的最大层次,也称为树的高度。

#include<stdio.h>
#include<stdlib.h>
typedef struct BiTNode{
	char data;
	struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
BiTree CreateBiTree(){
	BiTree T;
	char c;
	scanf("%c",&c);
	if('#'==c){
		T=NULL;
	}
	else{
	
		T=(BiTree)malloc(sizeof(BiTNode));
		T->data=c;
		T->lchild=CreateBiTree( );
		T->rchild=CreateBiTree( );
		}
		return T;
}
void visit(char data){
	printf("%c\n",data);
}
void PreOrderTrverse(BiTree T){
	if(T){
		visit(T->data);
		PreOrderTrverse(T->lchild);
		PreOrderTrverse(T->rchild);
	}
}
void InOrderTrverse(BiTree T){
	if(T){
		
		InOrderTrverse(T->lchild);
		visit(T->data);
		InOrderTrverse(T->rchild);
	}
}
//后序 
void PostOrderTrverse(BiTree T){
	if(T){
		
		PostOrderTrverse(T->lchild);
		PostOrderTrverse(T->rchild);
		visit(T->data);
	}
}
//树的深度 
int Depth(BiTree T){
	int m,n;
	if(T==NULL) return 0;
	else{
		m=Depth(T->lchild);
		n=Depth(T->rchild);
		if(m>n) return(m+1);
		else return(n+1);
	}
}
int main(){
	BiTree T;
	T=CreateBiTree();
	printf("先序遍历\n");
	PreOrderTrverse(T);
	printf("中序遍历\n");
	InOrderTrverse(T);
	printf("后序遍历\n");
	PostOrderTrverse(T);
	printf("%d",Depth(T));
	return 0;
}
//FCA##DB###EH##GM###

4.6线索二叉树

若结点有左孩子,则lchild之事其左孩子,否则lchild指向其前驱;若结点有右孩子,则rchild之事其左孩子,否则rchild指向其后继。
测试样例 FCA##DB###EH##GM###

#include <stdio.h>
#include <stdlib.h>
 
typedef char dataType;
typedef struct node
{
	dataType data; //根节点的值 
	struct node *lchild; //左孩子 
	struct node *rchild; //右孩子 
	int ltag; //左标记,“ltag=0”表示当前节点有左孩子,“ltag=1”表示当前节点没有左孩子 
	int rtag; //右标记,“rtag=0”表示当前节点有右孩子,“rtag=1”表示当前节点没有右孩子 
}BiTree; 

BiTree *creat() //二叉树的创建及初始化(初始化左右标记为0) 
{
	dataType value;
	BiTree *t;
	
	scanf("%c",&value);
	
	if(value=='#')
	{
		t=NULL;
	}
	else
	{
		t=(BiTree *)malloc(sizeof(BiTree));
		t->data=value;
		t->ltag=0;//初始化左标记为0 
		t->rtag=0;//初始化右标记为0 
		t->lchild=creat();
		t->rchild=creat();
	}
	return t;
}

//BiTree *pre=NULL; //1.定义全局变量pre
void InThreaded(BiTree *p)
{
	static BiTree *pre=NULL;//2.定义静态变量 	 
	if(p)
	{
		InThreaded(p->lchild);
		
		if(!p->lchild)
		{
			p->ltag=1;
			p->lchild=pre;
		}
		
		if(pre&&!pre->rchild)
		{
			pre->rtag=1;
			pre->rchild=p;
		}
		pre=p;
		
		InThreaded(p->rchild); 
	}
}

BiTree *Next(BiTree *t) //已知节点t找t的"后继"结点位置 
{   
	if(t->rtag==1) //右标志为1,可以直接得到"后继"结点 
	{
		t=t->rchild;
	 } 
	 else /*右标志为0,不能直接的到"后继"结点,
	        则需要找到右子树最左下角的节点*/ 
	{
	 	t=t->rchild;
		 while(t->ltag==0)
		{
		 	t=t->lchild;
		 } //while
	}//else
	return t;
}

BiTree *Prior(BiTree *t)//已知节点t找t的"前驱"结点位置 
{
	if(t->ltag==1)//左标志为1,可以直接找到"前驱"结点的位置 
	{
		t=t->lchild;
	 }
	else /*右标志为0,不能直接的到"前驱"结点,
	       则需要找到左子树最右下角的节点*/ 
	{
		t=t->lchild;
		while(t->rtag==0)
		{
			t=t->rchild;
		 } //while
	} //else
	
	return t;
}

void InorderTraverse(BiTree *t)//利用线索实现中序遍历 
{
	if(!t)
	{
		return;
	}
	
	while(t->ltag==0)//查找第一个节点 
	{               //因为二叉树的创建creat是以先序遍历序列创建,所以t所指向的第一个结点并不是中序遍历所要访问的第一个结点 
		t=t->lchild;
	}
	printf("%c ",t->data);//访问第一个结 
	while(t->rchild)// 此处以"t的右孩子不为空"为循环条件,是因为,先前设定了最后一个结点的"后继"为空,表示结束 
	{               //根据线索访问后续结点 
		t=Next(t);
		printf("%c ",t->data); 
	}
} 

int main() 
{
	BiTree *root;

    printf("Input:"); 
	root=creat();
	printf("\n");

	printf("Threading Binary Tree!\n");
	InThreaded(root);
	printf("\n");
	
	printf("Inorder traverse:");
	InorderTraverse(root);
	printf("\n");
	
	
	return 0;
}

//FCA##DB###EH##GM###

4.7编程HDU 1710

Javac++ 一天在看计算机的书籍的时候,看到了一个有趣的东西!每一串字符都可以被编码成一些数字来储存信息,但是不同的编码方式得到的储存空间是不一样的!并且当储存空间大于一定的值的时候是不安全的!所以Javac++ 就想是否有一种方式是可以得到字符编码最小的空间值!显然这是可以的,因为书上有这一块内容–哈夫曼编码(Huffman Coding);一个字母的权值等于该字母在字符串中出现的频率。所以Javac++ 想让你帮忙,给你安全数值和一串字符串,并让你判断这个字符串是否是安全的?
输入有多组case,首先是一个数字n表示有n组数据,然后每一组数据是有一个数值m(integer),和一串字符串没有空格只有包含小写字母组成!

输入样例
2 12 helloworld 66 ithinkyoucandoit
输出
no yes

#include <iostream>
   using namespace std;
   #define MAXNODE 10010
   struct HTNode{
       char data;        //节点值
     double weight;    //权重
      int parent;        //双亲节点 
      int lchild;        //左孩子节点
       int rchild;        //右孩子节点 
 }ht[2*MAXNODE-1];
  struct HCode{
      char cd[MAXNODE];
     int start;
 }hcd[MAXNODE];
  char str[MAXNODE];
 void CreateHT(HTNode ht[],int n)
  {
    int i,j,k,lnode,rnode;
     double min1,min2;
    for(i=0;i<2*n-1;i++)    //所有节点的相关域置初值-1 
        ht[i].parent = ht[i].lchild = ht[i].rchild = -1;
    for(i=n;i<2*n-1;i++){    //构造哈夫曼树 
          min1 = min2 = 9999999;    //lnode和rnode为权重最小的两个节点位置
          lnode = rnode =-1;
         for(k=0;k<=i-1;k++)
             if(ht[k].parent == -1){
                  if(ht[k].weight<min1){
                      min2 = min1;rnode = lnode;
                    min1 = ht[k].weight;lnode = k;
                 }
                 else if(ht[k].weight<min2){
                      min2 = ht[k].weight;rnode = k;
                  }
            } 
         ht[i].weight = ht[lnode].weight + ht[rnode].weight;
          ht[i].lchild = lnode;ht[i].rchild = rnode;    //ht[i]作为双亲节点
          ht[lnode].parent = i;ht[rnode].parent = i; 
      }
  }
  void CreateHCode(HTNode ht[],HCode hcd[],int n)
  {
      int i,f,c;
      HCode hc;    
     for(i=0;i<n;i++){    //根据哈夫曼树求哈夫曼编码      
         hc.start = n;c=i;
         f = ht[i].parent;
         while(f!=-1){
              if(ht[f].lchild == c)
                 hc.cd[hc.start--] = '0';
            else
                 hc.cd[hc.start--] = '1';
              c = f;f=ht[f].parent;
          }
          hc.start++;
          hcd[i]=hc;
     }
 }
  int main()
  {
      int n;
     cin>>n;
      while(n--){
         int m;
         cin>>m;
         cin>>str;
          int len = 0;
         for(int i=0;str[i];i++){    //初始化ht[]哈夫曼树的叶子节点和权值 
              //ht[]有无存储str[i]
             int j;
             for(j=0;j<len;j++)
                if(str[i]==ht[j].data)
                    break;
             if(j<len) continue;    //已经存储了,退出本次循环 
             int count = 0;
            for(j=0;str[j];j++){    //没存储,给ht[len]计数 
                 if(str[i]==str[j])
                     count++;
            }
             ht[len].data = str[i];
             ht[len++].weight = count;
        }
        //len--;
         CreateHT(ht,len);    //创建哈夫曼树 
        CreateHCode(ht,hcd,len);    //根据哈夫曼树求哈夫曼编码 
        if(len==1){    //只有一种字符的情况下,哈夫曼树是构造不起来的,特殊处理(直接进行比较) 
             if(ht[0].weight<=m)
                  cout<<"yes"<<endl;
              else
                 cout<<"no"<<endl;
              continue;
         }
         int wpl = 0;
          for(int i=0;i<len;i++){
             wpl += (len-hcd[i].start+1)*ht[i].weight;
         }
         //cout<<wpl<<endl;
        if(wpl<=m)
              cout<<"yes"<<endl;
        else 
            cout<<"no"<<endl;
    }
     return 0;
 }

4.8哈夫曼编码

/*示例 
****哈夫曼编码****
请输入结点个数:8
输入这8个元素的权值(均为整形):
1:27
2:4
3:87
4:21
5:2
6:21
7:1
8:25

*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct
{
  unsigned int weight;  //用来存储各个结点的权值 
  unsigned int parent,LChild,RChild;  //指向双亲、孩子结点的指针 
} HTNode, *HuffmanTree;  //动态分配数组,存储哈夫曼树 

typedef char *HuffmanCode;  //动态分配数组,存储哈夫曼树

///选择两个parent为0,且weight最小的结点s1和s2 
void Select(HuffmanTree *ht,int n,int *s1,int *s2)
{
 int i,min;
 for(i=1; i<=n; i++)
 {
   if((*ht)[i].parent==0)
   {
       min=i;
       break;
   }
 }
 for(i=1; i<=n; i++)
 {
    if((*ht)[i].parent==0)
	{
      if((*ht)[i].weight<(*ht)[min].weight)
      min=i;
	}
 }
 *s1=min;

 for(i=1; i<=n; i++)
 {
    if((*ht)[i].parent==0 && i!=(*s1))
	{
      min=i;
      break;
	}
 }
 for(i=1; i<=n; i++)
 {
    if((*ht)[i].parent==0 && i!=(*s1))
	{
      if((*ht)[i].weight<(*ht)[min].weight) 
		  min=i;
	}
 }
 *s2=min;
}

///构造哈夫曼树ht,w存放已知n个权值 
void CrtHuffmanTree(HuffmanTree *ht,int *w,int n)
{
 int m,i,s1,s2;
 m=2*n-1;    //总共的结点数 
 *ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
 for(i=1; i<=n; i++)  //1-n号存放叶子结点,初始化 
 {
  (*ht)[i].weight=w[i];
  (*ht)[i].LChild=0;
  (*ht)[i].parent=0;
  (*ht)[i].RChild=0;
 }
 for(i=n+1; i<=m; i++)   //非叶子结点的初始化
 {
  (*ht)[i].weight=0;
  (*ht)[i].LChild=0;
  (*ht)[i].parent=0;
  (*ht)[i].RChild=0;
 } 

 printf("\哈夫曼树为: \n");

 for(i=n+1; i<=m; i++)   //创建非叶子结点,建哈夫曼树
 { /*在(*ht)[1]~(*ht)[i-1]的范围内选择两个parent为0且weight最小的结点,其序号分别赋值给s1、s2*/
   Select(ht,i-1,&s1,&s2);
  (*ht)[s1].parent=i;
  (*ht)[s2].parent=i;
  (*ht)[i].LChild=s1;
  (*ht)[i].RChild=s2;
  (*ht)[i].weight=(*ht)[s1].weight+(*ht)[s2].weight;
  printf("%d (%d, %d)\n",(*ht)[i].weight,(*ht)[s1].weight,(*ht)[s2].weight);
 }
 printf("\n");
} 


//从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码
void CrtHuffmanCode(HuffmanTree *ht, HuffmanCode *hc, int n)
{
 char *cd;   //定义的存放编码的空间
 int a[100];
 int i,start,p,w=0;
 unsigned int c;
 hc=(HuffmanCode *)malloc((n+1)*sizeof(char *));  //分配n个编码的头指针
 cd=(char *)malloc(n*sizeof(char));  //分配求当前编码的工作空间
 cd[n-1]='\0';  //从右向左逐位存放编码,首先存放编码结束符

 for(i=1; i<=n; i++)  //求n个叶子结点对应的哈夫曼编码
 {
  a[i]=0;
  start=n-1;  //起始指针位置在最右边
  for(c=i,p=(*ht)[i].parent; p!=0; c=p,p=(*ht)[p].parent)  //从叶子到根结点求编码
  {
	
    if( (*ht)[p].LChild==c)
	{
		cd[--start]='1';  //左分支标1
		a[i]++;
	}
    else 
	{
		cd[--start]='0';  //右分支标0
		a[i]++;
	}
  }
  hc[i]=(char *)malloc((n-start)*sizeof(char));  //为第i个编码分配空间
  strcpy(hc[i],&cd[start]);    //将cd复制编码到hc
 }
 free(cd);
 for(i=1; i<=n; i++)
  printf(" 权值为%d的哈夫曼编码为:%s\n",(*ht)[i].weight,hc[i]);
 for(i=1; i<=n; i++)
    w+=(*ht)[i].weight*a[i];
 printf(" 带权路径为:%d\n",w);

}

int main()
{
 HuffmanTree HT;
 HuffmanCode HC;
 int *w,i,n,wei;

  printf("**哈夫曼编码**\n" );
 printf("请输入结点个数:" );
 scanf("%d",&n);
 w=(int *)malloc((n+1)*sizeof(int)); 
 printf("\n输入这%d个元素的权值:\n",n); 

 for(i=1; i<=n; i++)
 { 
  printf("%d: ",i); 
  fflush(stdin);
  scanf("%d",&wei);
  w[i]=wei;
 }
 CrtHuffmanTree(&HT,w,n);
 CrtHuffmanCode(&HT,&HC,n);
 
 system("pause");
 return 0;
}

5.图

5.1 kruasl算法

适合求稀疏网的最小生成树
测试数据:
6 10
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int parent[10];
int n,m;
int i,j;

struct edge{
	int u,v,w; //边的顶点,权值
}edges[10];

//初始化并查集
void UFset(){
	for(i=1; i<=n; i++) parent[i] = -1;
}

//查找i的根
int find(int i){
	int temp;
	//查找位置
	for(temp = i; parent[temp] >= 0; temp = parent[temp]);
	//压缩路径
	while(temp != i){   //表明没找到根节点,因为根节点的父节点是-1 
		int t = parent[i];
		parent[i] = temp;
		i = t;
	}
	return temp;
}
//合并两个元素a,b
void merge(int a,int b){
	int r1 = find(a);
	int r2 = find(b);
	int tmp = parent[r1] + parent[r2]; //两个集合节点数的和
	if(parent[r1] > parent[r2]){
		parent[r1] = r2;
		parent[r2] = tmp;
	}else{
		parent[r2] = r1;
		parent[r1] = tmp;
	}
}

void kruskal(){
	int sumWeight = 0;
	int num = 0;
	int u,v;
	UFset();
	for(int i=0; i<m; i++)
	{
		u = edges[i].u;
		v = edges[i].v;

		if(find(u) != find(v)){ //u和v不在一个集合,两者的根不同 
			printf("加入边:%d %d,权值: %d\n", u,v,edges[i].w);
			num ++;
			merge(u, v); //把这两个边加入一个集合。
		}
	}
	printf("最小生成树的权值之和为:%d \n", sumWeight);
}

//比较函数,用户排序
int cmp(const void * a, const void * b){
	edge * e1 = (edge *)a;
	edge * e2 = (edge *)b;
	return e1->w - e2->w;
}

int main() {

	scanf("%d %d", &n, &m);
	for(i=0; i<m; i++){
		scanf("%d %d %d", &edges[i].u,  &edges[i].v,  &edges[i].w);
	}
	qsort(edges, m, sizeof(edge), cmp);

	kruskal();

system("pause");
	return 0;
}
/*
测试数据:
6 10
1 2 6 
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6
 */

5.2图的遍历

邻接矩阵测试样例
1 2 3 4 5 6
1 2 6
1 4 5
1 3 1
2 3 5
3 4 5
4 5 3
3 5 6
3 6 4
4 6 2
5 6 6
邻接表测试样例
1 2
1 4
1 3
2 3
3 4
4 5
3 5
3 6
4 6
5 6

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
#define MaxInt 32767  //表示极大值
#define MVNum 100 //最大顶点数
#define OK 1
typedef char VerTexType;
typedef int  ArcType;
typedef int  status;
typedef int OtherInfo;						//和边相关的信息 
typedef struct
{
	char vexs[100];
	int arcs[100][100];
	int vexnum,arcnum;
}AMGraphy;
status LocateVex(AMGraphy G,VerTexType u)
{
	int i;
	for(i=0;i<G.vexnum;i++)
	  if(u==G.vexs[i]) return i;
	return -1;  
}
//邻接矩阵表示法
status CreateUDN(AMGraphy &G)
{
	cout <<"请输入总顶点数,总边数中间以空格隔开:";
   cin>>G.vexnum>>G.arcnum;   
   cout << "输入点的名称 " <<endl;
   for(int i=0;i<G.vexnum;i++)
     cin>>G.vexs[i];          
     
   for(int i=0;i<G.vexnum;i++)    //初始化邻接矩阵,边的权值均为Maxint 
      for(int j=0;j<G.vexnum;j++)
	    G.arcs[i][j]=MaxInt;
    for(int k=0;k<G.arcnum;k++)   //构造邻接矩阵 
	{
		char v1,v2;
		int w;
		cin>>v1>>v2>>w;       //输入一条边依附的顶点及权值 
		int i=LocateVex(G,v1);
		int j=LocateVex(G,v2); //确定v1,v1在G中的位置,即顶点数组的下标 
		G.arcs[i][j]=w;       //边<v1,v2>的权值置为w 
		G.arcs[j][i]=G.arcs[i][j];	//置<v1,v2>的对称边<v2,v1>的权值为w	
	}
	return OK;
}
//邻接表存储
typedef struct ArcNode{                		//边结点 
    int adjvex;                          	//该边所指向的顶点的位置 
    struct ArcNode *nextarc;          		//指向下一条边的指针 
    OtherInfo info;                      	//和边相关的信息 
}ArcNode; 

typedef struct VNode{ 
    VerTexType data;                    	//顶点信息 
    ArcNode *firstarc;                		//指向第一条依附该顶点的边的指针 
}VNode, AdjList[MVNum];               		//AdjList表示邻接表类型 

typedef struct{ 
    AdjList vertices;                 		//邻接表 
    int vexnum, arcnum;              		//图的当前顶点数和边数 
}ALGraph;
int LocateVex(ALGraph G , VerTexType v){
	//确定点v在G中的位置
	for(int i = 0; i < G.vexnum; ++i)
		if(G.vertices[i].data == v)
			return i;
   return -1;
}
int CreateUDG(ALGraph &G){ 
	//采用邻接表表示法,创建无向图G
	int i , k;

	cout <<"请输入总顶点数,总边数中间以空格隔开:";
	cin >> G.vexnum >> G.arcnum;				//输入总顶点数,总边数 
    cout << endl;
	
	cout << "输入点的名称 " <<endl;
	for(i = 0; i < G.vexnum; ++i){          	//输入各点,构造表头结点表
		cin >> G.vertices[i].data;           	//输入顶点值 
		G.vertices[i].firstarc=NULL;			//初始化表头结点的指针域为NULL 
    }//for
	cout << endl;
    
	cout << "请输入一条边依附的顶点,如 a b" << endl;
	for(k = 0; k < G.arcnum;++k){        
		VerTexType v1 , v2;
		int i , j;
		cin >> v1 >> v2;                 		//输入一条边依附的两个顶点
		i = LocateVex(G, v1);  j = LocateVex(G, v2);
		//确定v1和v2在G中位置,即顶点在G.vertices中的序号 

		ArcNode *p1=new ArcNode;               	//生成一个新的边结点*p1 
		p1->adjvex=j;                   		//邻接点序号为j 
		p1->nextarc= G.vertices[i].firstarc;  G.vertices[i].firstarc=p1;  
		//将新结点*p1插入顶点vi的边表头部

		ArcNode *p2=new ArcNode;                //生成另一个对称的新的边结点*p2 
		p2->adjvex=i;                   		//邻接点序号为i 
		p2->nextarc= G.vertices[j].firstarc;  G.vertices[j].firstarc=p2;  
		//将新结点*p2插入顶点vj的边表头部 
    }
    return OK; 
}
int main(){
	int choice;
	cout<<"输入选项 1:邻接矩阵 2:邻接表"<<endl; 
	cin>>choice;
	switch(choice){
		case 1:{
			AMGraphy G;CreateUDN(G);
			for (int i = 0; i < G.vexnum; ++i) {
        		for (int j = 0; j < G.vexnum; ++j) {
            		if (G.arcs[i][j]!=MaxInt){
                    	cout<<G.arcs[i][j]<<"\t";}
			 		else{cout << "∞" << "\t";}
            }
			cout<<endl;
        }
			break;
		}
	case 2:{
		ALGraph G;CreateUDG(G);
		cout << endl;
		for(int i = 0 ; i < G.vexnum ; ++i){
			VNode temp = G.vertices[i];
			ArcNode *p = temp.firstarc;
			if(p == NULL){
				cout << G.vertices[i].data;
				cout << endl;
			}
			else{
				cout << temp.data;
				while(p){
					cout << "->";
					cout << p->adjvex;
					p = p->nextarc;
				}
			}
			cout << endl;
		}
		break;
	}
	}
}
/*
1 2 3 4 5 6
1 2 6
1 4 5
1 3 1
2 3 5
3 4 5
4 5 3
3 5 6
3 6 4
4 6 2
5 6 6

1 2 
1 4
1 3
2 3
3 4
4 5
3 5
3 6
4 6
5 6
*/

5.3用邻接矩阵和邻接表来存储P166prim图,用DFS(递归和非递归方法)和BFS输出。

#include <iostream>
#include <stdio.h>
#include<queue>
#include <stdlib.h>
using namespace std;
#define MaxInt 32767  //表示极大值
#define MVNum 100 //最大顶点数
#define OK 1
typedef char VerTexType;
typedef int  ArcType;
typedef int  status;
typedef int OtherInfo;						//和边相关的信息 
typedef struct
{
	char vexs[MVNum];
	int arcs[MVNum][MVNum];
	int vexnum,arcnum;
}AMGraphy;
status LocateVex(AMGraphy G,VerTexType u)
{
	int i;
	for(i=0;i<G.vexnum;i++)
	  if(u==G.vexs[i]) return i;
	return -1;  
}
//邻接矩阵
status CreateUDN(AMGraphy &G)
{
	cout <<"请输入总顶点数,总边数中间以空格隔开:";
   cin>>G.vexnum>>G.arcnum;    //输入总顶点数,总边数 
   cout << "输入点的名称 " <<endl;
   for(int i=0;i<G.vexnum;i++)
     cin>>G.vexs[i];       
   for(int i=0;i<G.vexnum;i++)    //初始化邻接矩阵,边的权值均为Maxint 
      for(int j=0;j<G.vexnum;j++)
	    G.arcs[i][j]=MaxInt;

    for(int k=0;k<G.arcnum;k++)   //构造邻接矩阵 
	{
		char v1,v2;
		int w;
		cin>>v1>>v2>>w;       //输入一条边依附的顶点及权值 
		int i=LocateVex(G,v1);
		int j=LocateVex(G,v2); //确定v1,v1在G中的位置,即顶点数组的下标 
		G.arcs[i][j]=w;       //边<v1,v2>的权值置为w 
		G.arcs[j][i]=G.arcs[i][j];	//置<v1,v2>的对称边<v2,v1>的权值为w	
	}
	return OK;
}
//邻接表
typedef struct ArcNode{                		//边结点 
    int adjvex;                          	//该边所指向的顶点的位置 
    struct ArcNode *nextarc;          		//指向下一条边的指针 
    OtherInfo info;                      	//和边相关的信息 
}ArcNode; 

typedef struct VNode{ 
    VerTexType data;                    	//顶点信息 
    ArcNode *firstarc;                		//指向第一条依附该顶点的边的指针 
}VNode, AdjList[MVNum];               		//AdjList表示邻接表类型 

typedef struct{ 
    AdjList vertices;                 		//邻接表 
    int vexnum, arcnum;              		//图的当前顶点数和边数 
}ALGraph;
int LocateVex(ALGraph G , VerTexType v){
	//确定点v在G中的位置
	for(int i = 0; i < G.vexnum; ++i)
		if(G.vertices[i].data == v)
			return i;
   return -1;
}
int CreateUDG(ALGraph &G){ 
	//邻接表创建无向图G
	int i , k;
	cout <<"请输入总顶点数,总边数中间以空格隔开:";
	cin >> G.vexnum >> G.arcnum;				
    cout << endl;
	
	cout << "输入点的名称 " <<endl;
	for(i = 0; i < G.vexnum; ++i){          	//输入各点,构造表头结点表
		cin >> G.vertices[i].data;           	//输入顶点值 
		G.vertices[i].firstarc=NULL;			//初始化表头结点的指针域为NULL 
    }
	cout << endl;
    
	for(k = 0; k < G.arcnum;++k){        		//输入各边,构造邻接表
		VerTexType v1 , v2;
		int i , j;
		
		cin >> v1 >> v2;                 		//输入一条边依附的两个顶点
		i = LocateVex(G, v1);  j = LocateVex(G, v2);
		//确定v1和v2在G中位置,即顶点在G.vertices中的序号 

		ArcNode *p1=new ArcNode;               	//生成一个新的边结点*p1 
		p1->adjvex=j;                   		//邻接点序号为j 
		p1->nextarc= G.vertices[i].firstarc;  G.vertices[i].firstarc=p1;  
		//将新结点*p1插入顶点vi的边表头部

		ArcNode *p2=new ArcNode;                //生成另一个对称的新的边结点*p2 
		p2->adjvex=i;                   		//邻接点序号为i 
		p2->nextarc= G.vertices[j].firstarc;  G.vertices[j].firstarc=p2;  
		//将新结点*p2插入顶点vj的边表头部 
    }
    return OK; 
}
bool visited[MVNum]={false};

//邻接矩阵深度搜索 
void DFS_AM(AMGraphy &G,int v){
	cout<<v+1<<" ";visited[v]=true;
	for(int w=0;w<G.vexnum;w++)//依此检查邻接矩阵V所在的行 
		if((G.arcs[v][w]!=0)&&(!visited[w]) )DFS_AM(G,w);
		//G.arcs[v][w]!=0表示w是v的邻接点,如果w未访问,则递归调用DFS 
}

//邻接矩阵广度搜索 
void BFS_AM(AMGraphy G,int v)
{
	 for(int i=0;i<G.vexnum;i++)
	 	visited[i]=false;
	cout<<v+1<<" ";visited[v]=true;//访问第v个顶点 
	queue<int> Q;        //辅助队列Q初始化 
	Q.push(v);           //v进队 
	while(!Q.empty())    //队列非空 
	{
		int t=Q.front();
		Q.pop();         //队头元素出队并赋给t 
		for(int w=0;w<G.vexnum;w++)
		{
			if(G.arcs[t][w]!=0 && visited[w]==false)
			{
				visited[w]=true;
				cout<<w+1<<" ";
				Q.push(w);//w进队 
			}
		}
	}
}
//邻接表深度搜索 
void DFS_AL(ALGraph G,int v)
{
	ArcNode *p;
	p=new ArcNode;
	cout<<v+1<<" ";visited[v]=true;
	p=G.vertices[v].firstarc;
	while(p!=NULL)
	{
		int w=p->adjvex;
		if(!visited[w]) DFS_AL(G,w);
		p=p->nextarc;
	}	
}
//邻接表广度搜索 
void BFS_AL(ALGraph G,int v)
{
	
	for(int i=0;i<G.vexnum;i++)
	 visited[i]=false;
	 
	 cout<<v+1<<" ";
	 visited[v]=true;
	 queue<int> Q;
	 Q.push(v);
	 ArcNode *p;
	 p=new ArcNode;
	 while(!Q.empty())
	 {
	 	int t=Q.front();
	 	Q.pop();
	 	for(p=G.vertices[t].firstarc;p!=NULL;p=p->nextarc)
	 	{
           if(!visited[p->adjvex])
		   {
		   	  cout<<(p->adjvex)+1<<" ";
		   	  visited[p->adjvex]=true;
		   	  Q.push(p->adjvex);
		    }	 	 	
		}
	 }
}
int main(){
	int choice;
	cout<<"输入选项 1:邻接矩阵 2:邻接表"; 
	cin>>choice;
	switch(choice){
		case 1:{
			AMGraphy G;CreateUDN(G);
        	cout<<"DFS遍历结果为:"<<endl;
			DFS_AM(G,2);
			cout<<endl;
			cout<<"BFS遍历结果为:"<<endl;
			BFS_AM(G,1);
			break;
	}
	case 2:{
		ALGraph G;
		CreateUDG(G);
		cout << endl;
		cout<<"深度优先搜索结果是"<<endl;
		DFS_AL(G,2);
        cout<<endl;
		cout<<"广度优先搜索结果是"<<endl;
		BFS_AL(G,2);
		cout << endl;
	}
		break;
	}
	return 0;
}

/*
邻接矩阵 
6 10
1 2 3 4 5 6
1 2 6
1 4 5
1 3 1
2 3 5
3 4 5
4 5 3
3 5 6
3 6 4
4 6 2
5 6 6
邻接表 
1 2 
1 4
1 3
2 3
3 4
4 5
3 5
3 6
4 6
5 6
*/

5.4关键路径的实现

估算工程完成的最短时间,既是找从源点到汇点的带权路径长度最长的路径,称为关键路径

#include <cstdio>
#include <cstring>
#define MAXN 100 //The Max num of Vertex
#define MAXM 200 //The Max num of Edges
using namespace std;
 
struct ArcNode //保存边的信息
{
    int to, dur, no;
    //to: next vertex, dur: the duration of the activities; no: the ID of activity
    struct ArcNode *next;
};
 
//全局变量!
int n,m; //the number of Vertex and Edge,
ArcNode* outEdge[MAXN]; //记录每个顶点对应的出边表
ArcNode* inEdge[MAXN]; //记录每个顶点对应的入边表
int outOrd[MAXN]; //每个顶点的出度
int inOrd[MAXN]; //每个顶点的入度
int ev[MAXN]; //Earliest start time for Vertex
int lv[MAXN]; //Latest start time for Vertex
int ee[MAXM]; //MAXM!! Earliest start time for Edge
int le[MAXM]; //Latest start time for Edge!!
 
void CriticalPath()
{
    int i; //循环变量
    int tmp,nxt; //临时变量
    int top=-1; //top指示栈顶的位置;-1表示栈空,正整数表示下一个入度(或出度)为零的点的位置
    ArcNode* tpNode;
    for(i=0;i<n;i++) //扫描inOrd;把所有入度为0的点入栈(一个虚拟的栈,以top表示下一个数据的位置)
    {
        if(inOrd[i]==0)
        {
            inOrd[i]=top; //因为inOrd为0,失去了意义,所以正好可以以此来保存栈中下一个元素的位置
            top=i; //以这种类似于堆栈的方式,保存所有入度为0的点
        }
    }
 
    //可以明确的是,如果不存在环的话,必然每个顶点都会遍历一次,所以这里可以做一个循环
    //如果循环结束前,入度为0的点就用尽的话,必然是有环的
    for(i=0;i<n;i++)
    {
        if(-1==top)
        {
            printf("Cycle Detected!!\n");
            return;
        }
        else
        {
            tmp=top; //tmp记录当前需要处理的顶点号,即入度为0的点
            top=inOrd[top];//top中保存下一个入度为0的元素位置
            tpNode=outEdge[tmp];//取出入度为零点的出边链表
            while(tpNode!=NULL)
            {
                nxt=tpNode->to;
                inOrd[nxt]--; //从该点出发的所有终点的入度减1
                if(0==inOrd[nxt]) //若出现新的入度为零的点,则入栈
                {
                    inOrd[nxt]=top;
                    top=nxt;
                }
 
                //其它的都是套路(实现拓扑排序的套路),下面这两句才是为求关键路径而生的
                //下一个点的最早开始时间,必然是上一个点的最早开始时间+活动持续时间
                //如果到达该点有多个路径,最早开始时间必然是个值中的最大值!(因为有一条路径未完成,该点就不能启动)
                //第一个起点的ev值,在初始化时就被设为0了
                if(ev[nxt]<tpNode->dur+ev[tmp])
                    ev[nxt]=tpNode->dur+ev[tmp];
 
                tpNode=tpNode->next;
            }
        }
    }
 
 
    //以入度邻接表,再来一遍
    int maxtime=0;
    for(i=0;i<n;i++)  //找出工程所需时间(总时间)
        if(ev[i]>maxtime)
            maxtime=ev[i];
 
    top=-1; //重新设栈顶
    for(i=0; i<n; i++)
    {
        lv[i]=maxtime; //先将所有节点的最迟开始时间都设为最后时间
        if(0==outOrd[i]) //依然是设栈,解释见上面雷同程序
        {
            outOrd[i]=top;
            top=i;
        }
    }
    for(i=0; i<n; i++)
    {
        if(-1==top)
        {
            printf("Back Cycle Detected.\n");
            return;
        }
        else
        {
            tmp=top; 
            top=outOrd[top];
            tpNode=inEdge[tmp];
            while(tpNode!=NULL)
            {
                nxt=tpNode->to; //其实是找上一个点
                outOrd[nxt]--;
                if(0==outOrd[nxt])
                {
                    outOrd[nxt]=top;
                    top=nxt;
                }
                //下面两句计算最迟开始时间
                //只要有一条路径决定它在更早的时间开始,就得更早开始,所以取各路径最小值
                if(lv[nxt]>(lv[tmp]-tpNode->dur))
                    lv[nxt]=(lv[tmp]-tpNode->dur);
 
                tpNode=tpNode->next;
            }
        }
    }
 
    //上面计算的都是节点(!)的最早和最迟开始时间,下面需要计算边的
    //若边(活动)的最早开始==最迟开始时间,则该边为关键路径
    printf("The Critical Path:\n");
    for(i=0; i<n; i++)  //通过出边表,遍历每条边!!(但必须从顶点入手,理出每个顶点的出边表)
    {
        tpNode=outEdge[i];
        while(tpNode!=NULL)
        {
            tmp=tpNode->no; //tmp此时保存边的编号!!
            nxt=tpNode->to;
            ee[tmp]=ev[i];//边的最早开始时间就是其起点的最早开始时间
            le[tmp]=lv[nxt]-tpNode->dur; //边的最迟开始时间,是其终点的最迟开始时间减去边的持续时间
            if(ee[tmp]==le[tmp])
                printf("a%d:%d->%d\n",tmp,i,nxt);
            tpNode=tpNode->next;
        }
    }
}
 
 
int main()
{
    int i;
    int s,e,t; //start point; end point; time needed
    ArcNode* newNode; //只定义,未初始化
 
    memset(outEdge, NULL, sizeof(outEdge));
    memset(inEdge, NULL, sizeof(inEdge));
    memset(outOrd, 0, sizeof(outOrd)); //必须初始化为0
    memset(inOrd,0, sizeof(inOrd));
    memset(ev,0,sizeof(ev));
    memset(lv,0,sizeof(lv));
    memset(ee,0,sizeof(ee));
    memset(le,0,sizeof(le));
    printf ("输入顶点数和边数\n");
    scanf("%d %d",&n,&m); //读入输入数据,共计n个顶点和m条边
    printf("输入依附的顶点及权值\n");
    for(i=0;i<m;i++)
    {
        scanf("%d%d%d",&s,&e,&t);
 
        //构建出边表
        outOrd[s]++; //起点的出度增加
        newNode=new ArcNode; //初始化赋值
        newNode->to=e;
        newNode->no=i+1; //这个是边的编号,第一条读入的边作为1号边
        newNode->dur=t;
        newNode->next=NULL; //NULL需要大写!
        if(outEdge[s]==NULL)  //没有之前的出边,则直接赋值;若有,则需像挂接火车车厢一样,挂接链表
            outEdge[s]=newNode;
        else
        {
            newNode->next=outEdge[s];
            outEdge[s]=newNode;
        }
 
        //构建入边表
        inOrd[e]++;
        newNode=new ArcNode; // 必须重新赋值
        newNode->to=s;
        newNode->no=i+1;
        newNode->dur=t;
        newNode->next=NULL;
        if(inEdge[e]==NULL)
            inEdge[e]=newNode;
        else
        {
            newNode->next=inEdge[e];
            inEdge[e]=newNode;
        }
    }
 
    //一次性获得全部输入后,执行程序的核心部分——找出关键路径
    CriticalPath();
 
    //Release the Memory
    for(i=0;i<n;i++)
    {
        while(outEdge[i]!=NULL)
        {
            newNode=outEdge[i]->next;  //newNode不是新节点,只是借用一下其名字
            delete outEdge[i];
            outEdge[i]=newNode;
        }
 
        while(inEdge[i]!=NULL)
        {
            newNode=inEdge[i]->next;
            delete inEdge[i];
            inEdge[i]=newNode;
        }
    }
    return 0;
}
/*
9 11
0 1 6
1 4 1
4 6 9
6 8 2
0 2 4
2 4 1
4 7 7
7 8 4
0 3 5
3 5 2
5 7 4
*/

5.5dijstra非文件读取

单源点到其余各个顶点的最短路径问题

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
#define MaxInt 32767  //表示极大值
#define MVNum 100 //最大顶点数
#define OK 1
typedef char VerTexType;
typedef int  ArcType;
typedef int  status;
typedef int OtherInfo;						//和边相关的信息 
typedef struct
{
	char vexs[100];
	int arcs[100][100];
	int vexnum,arcnum;
}AMGraph;
status LocateVex(AMGraph G,VerTexType u)
{
	int i;
	for(i=0;i<G.vexnum;i++)
	  if(u==G.vexs[i]) return i;
	return -1;  
}
//邻接矩阵表示法
status CreateUDN(AMGraph &G)
{
	cout <<"请输入总顶点数,总边数中间以空格隔开:";
   cin>>G.vexnum>>G.arcnum;   
   cout << "输入点的名称 " <<endl;
   for(int i=0;i<G.vexnum;i++)
     cin>>G.vexs[i];          
     
   for(int i=0;i<G.vexnum;i++)    //初始化邻接矩阵,边的权值均为Maxint 
      for(int j=0;j<G.vexnum;j++)
	    G.arcs[i][j]=MaxInt;
    for(int k=0;k<G.arcnum;k++)   //构造邻接矩阵 
	{
		char v1,v2;
		int w;
		cin>>v1>>v2>>w;       //输入一条边依附的顶点及权值 
		int i=LocateVex(G,v1);
		int j=LocateVex(G,v2); //确定v1,v1在G中的位置,即顶点数组的下标 
		G.arcs[i][j]=w;       //边<v1,v2>的权值置为w 
		G.arcs[j][i]=G.arcs[i][j];	//置<v1,v2>的对称边<v2,v1>的权值为w	
	}
	return OK;
}

void ShortestPath_DTJ(AMGraph G,int v0){
	int n=G.vexnum;//顶点数 
	int S[n],Path[n],i,v,w,D[n],min,sum;
	for(int v=0;v<n;v++){
		S[v]=0;D[v]=G.arcs[v0][v];//S[i]=1表示点已知 
		if(D[v]<MaxInt)   //有弧 
			Path[v]=v0;  //点的前驱 
		else Path[v]=-1;
	}
	S[v0]=1;D[v0]=0;
	//初始化结束 
	for( i=1;i<n;i++){
		min=MaxInt;
		for( w=0;w<n;w++){
			if(!S[w]&&D[w]<min)
				v=w;min=D[w];
		}
		S[v]=1;
		for(w=0;w<n;w++){
			if(!S[w]&&(D[v]+G.arcs[v][w])<D[w]){
				D[w]=D[v]+G.arcs[v][w];
				Path[w]=v;
			}
		}
	}
	
	cout<<D[4];
}
int main(){
	AMGraph G;
	CreateUDN(G);
	ShortestPath_DTJ(G,0);
	return 0;
}
/*
5 7
0 1 2 3 4
0 1 10
0 2 3
0 3 20
1 3 5
2 1 2
2 4 15
3 4 11
结果:18 
*/

5.6 dijstra算法文件读取实现

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
#define N 100 //最大顶点数
FILE *fr,*fw;
typedef struct //边 的信息 
{
	int u,v;//顶点 
	int dist;//权值 
}Edge;	
Edge edge[N];
//最短路径算法 
void ShortestPath_DTJ(){
	int i,j,dis[N],pre[N];
	int n,e,o,p;  //顶点数 边数 起点 终点 
	fr=fopen("C:/Users/dell/Desktop/dijstra.txt","r");
	for(i=1;i<=e+1;i++)//输入边的信息(点,权值) 
	{
		if(i==1) fscanf(fr,"%d%d%d%d",&n,&e,&o,&p);
		else fscanf(fr,"%d%d%d",&edge[i].u,&edge[i].v,&edge[i].dist);
	}
	fclose(fr);
	pre[o]=o; 
	for(i=1;i<=n;i++)//初始化
		dis[i] = (i == o ? 0 : 1000);
	for(i=1;i<=n-1;i++)
	{
		for(j=1;j<=e;j++)
		{
			if(dis[edge[j].v]>dis[edge[j].u]+edge[j].dist)
			{
				dis[edge[j].v]=dis[edge[j].u]+edge[j].dist;
				pre[edge[j].v]=edge[j].u;
			}
		}
	}
	
	fw=fopen("C:/Users/dell/Desktop/out.txt","w+");
	for(int i=1;i<=n;i++)
		{
			if(i==p)
			{
				fprintf(fw,"V%d到V%d的最短距离为:%d\n",o,i,dis[i]);
			}
		}
}
int main(){
	ShortestPath_DTJ();
	return 0;
}

在这里插入图片描述

5.7 拓扑排序算法实现

拓扑排序即是将AOV-网中所有顶点排成一个线性序列。AOV-网即是用顶点表示活动,用弧表示活动间的优先关系的有向图

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAXVEX 20
typedef char VerType;	//顶点值类型

struct EdgeNode{
	int adjvex;	//邻接点域,存储该顶点对应的下标
	int weight;	//用于存储权值,对于非网图可以不需要
	EdgeNode* next;	//下一个结点 
};

struct VertexNode{
	int in;	//入度
	VerType data;	//值
	EdgeNode* firstedge;	//邻接表头指针 
}; 

struct Graph{
	VertexNode vers[MAXVEX];
	int numVertexes, numEdges;	//顶点数和边数 
};

//拓扑排序,若G没有回路,则输出拓扑排序序列并返回OK,若有回路返回ERROR 
bool TopologicalSort(Graph* G){
	EdgeNode* e;
	int i, k, gettop;
	int top = 0;	//栈指针下标
	int count = 0;	//统计输出顶点个数
	int* stack;	//存储入度为0的顶点
	stack = (int*)malloc(G->numVertexes * sizeof(int));
	
	for(i = 0;i<G->numVertexes;i++)	//遍历所有结点 
		if(G->vers[i].in == 0)
			stack[++top] = i;	//将入度为0的顶点入栈

	while(top != 0){
		gettop = stack[top--];	//出栈
		printf("%c ",G->vers[gettop].data);
		count++;	//统计输出顶点数
		for(e=G->vers[gettop].firstedge; e; e = e->next){
			//弧表遍历
			k = e->adjvex;
			if(!(--G->vers[k].in))	//将k号顶点邻接点的入度减1
				stack[++top] = k;	//若为0则入栈,以便下次循环输出 
		}
	}
	if(count < G->numVertexes)	//如果count小于顶点数,说明存在环
		return false;
	else
		return true; 
}

/* 图初始化 */
void CreateGraph(Graph* G){
	int i, m, n;
	
	printf("输入顶点数和边数:\n");
	scanf("%d %d",&G->numVertexes, &G->numEdges);
	printf("输入顶点值:\n");
	for(i=0;i<G->numVertexes;i++){
		getchar();	//吃掉回车
		scanf("%c",&G->vers[i].data);
	}
	//初始化图头结点指针和入度值 
	for(i=0;i<G->numVertexes;i++){
		G->vers[i].firstedge = NULL;
		G->vers[i].in = 0;	//入度为0 
	}
	printf("输入边:\n");
	for(i=0;i<G->numEdges;i++){
		scanf("%d %d",&m, &n);
		EdgeNode* newNode = (EdgeNode*)malloc(sizeof(EdgeNode));
		newNode->next = G->vers[m].firstedge == NULL ? NULL : G->vers[m].firstedge;
		newNode->adjvex = n;
		G->vers[m].firstedge = newNode;
		G->vers[n].in++;	//入度+1 
	}
}

int main(){
	
	Graph* G = (Graph*)malloc(sizeof(Graph));
	CreateGraph(G);
	if(TopologicalSort(G)){
		printf("拓扑排序完成!\n");
	}else{
		printf("图存在环");
	}
	return 0;
}
/*
6 8
a
b
c
d
e
f
0 1
0 2
0 4
1 3
3 2
2 4
4 5
3 5
结果 a b d c e f 拓扑排序完成!
12 16
a
b
c
d
e 
f 
g 
h 
i 
j
k  
l 
0 3
3 4
0 1
1 2
2 4
2 6
4 6
0 2
0 11
2 7
8 11
8 9
9 11
8 10
10 5
5 7
i j k f a d b c e g h l   
*/

6.查找

6.1用递归和非递归实现二分查找

二分查找又称折半查找,要求线性表采用顺序存储,且表中元素按关键字有序排列
测试样例:
6
1 4 5 6 7 9
5

#include<stdio.h>
#define MAXSIZE 50
#define Status int
#define InfoType int 
typedef struct{
	int key;
	InfoType otherinfo;
}ElemType;
typedef struct{
	ElemType *R;
	int length;
}SSTable;
//顺序表初始化 
Status InitList(SSTable &ST){
	ST.R=new ElemType[MAXSIZE];
	ST.length=0;
	return 1;
} 
//二分查找非递归 
int Search_Bin(SSTable ST,int key){
	int low=1,high=ST.length,mid;
	while(low<=high){
		mid=(low+high)/2;
		if(key==ST.R[mid].key)return mid;
		else if(key<ST.R[mid].key) high=mid-1;
		else low=mid+1;
	}
	return 0;
}
//递归 
int Search(SSTable ST,int low,int high,int key){
	int mid;
	while(low<=high){
		mid=(low+high)/2;
		if(key==ST.R[mid].key)return mid;
		else if(key<ST.R[mid].key) {
			high=mid-1;
			return Search(ST,low,high,key);
		}
		else {
			low=mid+1;
			return Search(ST,low,high,key);
		}
	}
	return 0;
}
int main(){
	SSTable ST;
	InitList(ST);
	int n, i=1,s,key,choice;
	printf("请输入表的长度:\n");
	scanf("%d", &n);
	for(i=1;i<=n;i++)
		scanf("%d",&ST.R[i].key);
	printf("请输入要查找的数:\n");
	scanf("%d", &key);
	ST.length=n;
	printf("输入选项 1:非递归      2:递归\n");
	scanf("%d",&choice);
	switch(choice){
		case 1:if(Search_Bin(ST,key)!=0){printf("已找到,在表中%d位",Search_Bin(ST,key));}
			   else printf("未找到");
		       break;
		case 2:if(Search(ST,1,n,key)!=0){printf("已找到,在表中%d位",Search(ST,1,n,key));break;}
				else printf("未找到");
				break;
	}
	return 0;
}

6.2

8.其他

81学生成绩管理系统

#include <stdio.h>
#include <stdlib.h> 
#include <string.h>

//定义学生结构体 
struct Student { 
     char ID[20]; 
     char Name[20]; 
     float Mark1; 
     float Mark2; 
     float Mark3; 
     float Average; 
};  
//声明学生数组及学生数量 
struct Student students[1000]; 
int num=0; 
//求平均值/
float Avg(struct Student stu) { 
     return (stu.Mark1+stu.Mark2+stu.Mark3)/3; 
} 
//通过学号返回数组下标 
int Student_SearchByIndex(char id[]) { 
     int i; 
     for (i=0;i<num;i++) 
     {
          if (strcmp(students[i].ID,id)==0) 
         { 
              return i; 
         } 
     }
      return -1;
 
} 
//通过姓名返回数组下标 
int Student_SearchByName(char name[]) { 
     int i; 
     for (i=0;i<num;i++) 
     { 
         if (strcmp(students[i].Name,name)==0) 
         { 
              return i; 
         } 
     } 
     return -1; 
} 
//显示单条学生记录 
void Student_DisplaySingle(int index) 
{ 
     printf("%10s%20s%16s%16s%16s%20s\n","学号","姓名","数学成绩","英语成绩","C语言成绩","平均成绩");
     printf("-------------------------------------------------------------\n");
     printf("%10s%20s%16.2f%16.2f%16.2f%20.2f\n",students[index].ID,students[index].Name, 
              students[index].Mark1,students[index].Mark2,students[index].Mark3,students[index].Average);
}
//插入学生信息
void Student_Insert(){ 
     while(1){ 
         printf("请输入学号:"); 
         scanf("%s",&students[num].ID); 
         getchar(); 
         printf("请输入姓名:"); 
         scanf("%s",&students[num].Name); 
         getchar(); 
         printf("请输入数学成绩:"); 
         scanf("%f",&students[num].Mark1);
         getchar();
         printf("请输入英语成绩:"); 
         scanf("%f",&students[num].Mark2); 
         getchar(); 
         printf("请输入C语言成绩:"); 
         scanf("%f",&students[num].Mark3); 
         getchar(); 
         students[num].Average=Avg(students[num]); 
         num++; 
         printf("是否继续?(y/n)"); 
         if (getchar()=='n'){ 
              break; 
         } 
     } 
}
//修改学生信息
void Student_Modify(){ 
     while(1) { 
         char id[20]; 
         int index; 
         printf("请输入要修改的学生的学号:"); 
         scanf("%s",&id); 
         getchar(); 
         index=Student_SearchByIndex(id); 
         if (index==-1){ 
              printf("学生不存在!\n");
         } 
         else
         { 
              printf("你要修改的学生信息为:\n"); 
              Student_DisplaySingle(index); 
              printf("-- 请输入新值--\n"); 
              printf("请输入学号:"); 
              scanf("%s",&students[index].ID); 
              getchar(); 
              printf("请输入姓名:"); 
              scanf("%s",&students[index].Name); 
              getchar(); 
              printf("请输入数学成绩:"); 
              scanf("%f",&students[index].Mark1); 
              getchar(); 
              printf("请输入英语成绩:"); 
              scanf("%f",&students[index].Mark2); 
              getchar(); 
              printf("请输入C语言成绩:"); 
              scanf("%f",&students[index].Mark3); 
              getchar(); 
              students[index].Average=Avg(students[index]); 
         } 
         printf("是否继续?(y/n)"); 
         if (getchar()=='n'){ 
              break; 
         } 
     } 
}
//删除学生信息 
void Student_Delete(){ 
     int i; 
     while(1){ 
         char id[20]; 
         int index; 
         printf("请输入要删除的学生的学号:"); 
         scanf("%s",&id); 
         getchar(); 
         index=Student_SearchByIndex(id); 
         if (index==-1){ 
              printf("学生不存在!\n"); 
         } 
         else{ 
              printf("你要删除的学生信息为:\n"); 
              Student_DisplaySingle(index); 
              printf("是否真的要删除?(y/n)"); 
              if (getchar()=='y'){ 
                   for (i=index;i<num-1;i++){ 
                       students[i]=students[i+1];//把后边的对象都向前移动 
                   } 
                   num--; 
              } 
              getchar(); 
         } 
         printf("是否继续?(y/n)"); 
         if (getchar()=='n'){ 
              break; 
         } 
     } 
}
//按姓名查询
void Student_Select(){ 
     while(1){ 
         char name[20]; 
         int index; 
         printf("请输入要查询的学生的姓名:"); 
         scanf("%s",&name); 
         getchar(); 
         index=Student_SearchByName(name); 
         if (index==-1){ 
              printf("学生不存在!\n"); 
         } 
         else 
         { 
              printf("你要查询的学生信息为:\n"); 
              Student_DisplaySingle(index); 
         } 
         printf("是否继续?(y/n)"); 
         if (getchar()=='n'){ 
              break; 
         }
    } 
}
//按平均值排序 
void Student_SortByAverage(){ 
     int i,j; 
     struct Student tmp; 
     for (i=0;i<num;i++){ 
         for (j=1;j<num-i;j++){ 
              if (students[j-1].Average<students[j].Average) 
              {
			       tmp=students[j-1]; 
                   students[j-1]=students[j]; 
                   students[j]=tmp; 
              } 
         } 
     } 
}
//显示学生信息 
void Student_Display(){ 
     int i; 
     printf("%20s%20s%16s%16s%16s%20s\n","学号","姓名","数学成绩","英语成绩","C语言成绩","平均成绩"); 
     printf("-------------------------------------------------------------\n"); 
     for (i=0;i<num;i++) { 
         printf("%20s%20s%16.2f%16.2f%16.2f%20.2f\n",students[i].ID,students[i].Name, 
              students[i].Mark1,students[i].Mark2,students[i].Mark3,students[i].Average); 
     } 
}
//将学生信息从文件读出
void IO_ReadInfo(){ 
     FILE *fp; 
     int i; 
     if ((fp=fopen("Database.txt","rb"))==NULL){ 
         printf("不能打开文件!\n"); 
         return; 
     }
 
     if (fread(&num,sizeof(int),1,fp)!=1){ 
         num=-1; 
     } 
     else{ 
         for(i=0;i<num;i++) 
         { 
              fread(&students[i],sizeof(struct Student),1,fp); 
         } 
     } 
     fclose(fp); 
}
//将学生信息写入文件
void IO_WriteInfo(){ 
     FILE *fp; 
     int i; 
     if ((fp=fopen("Database.txt","wb"))==NULL){ 
         printf("不能打开文件!\n"); 
         return; 
     } 
     if (fwrite(&num,sizeof(int),1,fp)!=1){ 
         printf("写入文件错误!\n"); 
     } 
     for (i=0;i<num;i++){ 
         if (fwrite(&students[i],sizeof(struct Student),1,fp)!=1) 
         { 
              printf("写入文件错误!\n"); 
         }
     }    
    fclose(fp); 
}

//主程序 
int main(){ 
     int choice; 
     IO_ReadInfo(); 
     while(1) { 
         printf("\n------ 河南理工大学学生成绩管理系统------\n"); 
         printf("1. 增加学生记录\n"); 
         printf("2. 修改学生记录\n"); 
         printf("3. 删除学生记录\n"); 
         printf("4. 按姓名查询学生记录\n"); 
         printf("5. 按平均成绩排序\n"); 
         printf("6. 退出\n"); 
         printf("请选择(1-6):"); 
         scanf("%d",&choice); 
         getchar(); 
         switch(choice){ 
         case 1: 
              Student_Insert(); 
              break; 
         case 2: 
              Student_Modify(); 
              break; 
         case 3: 
              Student_Delete(); 
              break; 
         case 4: 
              Student_Select(); 
              break; 
         case 5: 
              Student_SortByAverage(); 
              Student_Display(); 
              break; 
         case 6: 
              exit(0); 
              break; 
         } 
         IO_WriteInfo(); 
     }
return 0; 
}

8.2快速排序时间计算

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
	void quicksort(int a[], int L, int R);
	clock_t start_t, finish_t;
	double total_t = 0;
	FILE* fp;
	int n, i;
	int* a;
	printf("请输入所要读取的数量:\n");
	scanf("%d", &n);
	a = (int*)malloc(n * sizeof(int));
	start_t = clock();
	fp = fopen("100000.txt", "r");
	for (i = 0; i < n; i++)
		fscanf(fp, "%d ", &a[i]);
	
	quicksort(a, 0, n - 1);
	//for (i = 0; i < n; i++)
		//printf("%d ", a[i]);
	finish_t = clock();
	total_t = (double)(finish_t - start_t) / CLOCKS_PER_SEC;//将时间转换为秒
	printf("CPU 占用的总时间:%lf\n", total_t);
	fclose(fp);
	return 0;
}
	/*240.336*/
	
void quicksort(int a[], int low, int high)
{
    int i = low;
    int j = high;
    int temp = a[low];
    while (i < j) {
        while (i < j && a[j] > temp) j--;
        if (i < j) { a[i++] = a[j];
        
        }
        while (i<j && a[i]<temp) i++;
        if (i < j) { a[j--] = a[i]; 
        }
    }
    a[i] = temp;
    if (low >= high) return;
    else {
        quicksort(a, low, i - 1);
        quicksort(a, i + 1, high);
    }
}

8.3冰雹猜想

一个正整数,如果是奇数,则乘以3再加1,如果是偶数就除以2,若干次后变为1,求进行的次数

#include <stdio.h>
#include <stdlib.h>
int main(){
	int n,time=0;
	while(scanf("%d",&n),n){
		while(n!=1){
			if(n&1){
				n=3*n+1;
			}
			else{
				n>>=1;
			}
			time++;
		}
		printf("%d",time);
	}
	return 0;
}

5.4结构体输入输出

#include<stdio.h>
struct students{
	char name[10];
	float math;
}stu[200];
int main(){
	int n,i;
	printf("输入个数");
	scanf("%d",&n);
	for(i=0;i<n;i++){
		printf("输入姓名 成绩");
		scanf("%s %f\n",&stu[i].name,&stu[i].math);
	}
	for(i=0;i<n;i++){
		printf("%s %f\n",stu[i].name,stu[i].math);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值