数据结构
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;
}