数据结构实验

实验1:线性表

基本就是按照思路直接写

代码:
#include<iostream>
#include<fstream>
#include<cstring>
#include<iomanip>
using namespace std;

#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;		  //Status 是函数返回值类型,其值是函数结果状态代码。
                        //typedef int ElemType;   //ElemType 为可定义的数据类型,此设为int类型

#define MAXSIZE 100     //表可能达到的最大长度
typedef struct
{
    char no[8];          //8位学号
    char name[80];       //姓名
    int  grade;          //成绩
}Student;

//顺序表的定义(第一个程序用)
typedef  struct
{
    Student* elem;     //指向数据元素的基地址
    int  length;        //线性表的当前长度                                                           
}SqList;

//主函数,因为函数声明,故可放其他函数之前
int  main()
{
    SqList L;
    int i, choose;
    char name[80];

    //功能定义,声明函数
    Status  InitList(SqList & L);				//初使化顺序表
    Status  CreatList(SqList & L);				//构建顺序表
    Status  TraverseList(SqList L);				//显示
    Status  LocateElem(SqList L, char* name);	//查找
    Status  GetElem(SqList L, int i);			//获取
    Status  ListInsert(SqList & L, int i);		//插入
    Status  ListDelete(SqList & L, int i);		//删除
    int  ListLength(SqList L);				//顺序表长度
    Status  DestroyList(SqList & L);				//销毁顺序表

                                                //屏幕提示操作!
    cout << "---------------------\n";
    cout << "1. 初使化顺序表\n";
    cout << "2. 构建顺序表\n";
    cout << "3. 显示顺序表长度\n";
    cout << "4. 显示顺序表内容\n";
    cout << "5. 查找学生信息\n";
    cout << "6. 获取学生信息\n";
    cout << "7. 插入学生信息\n";
    cout << "8. 删除学生信息\n";
    cout << "9. 销毁顺序表\n";
    cout << "0. 退出\n\n";
    cout << "---------------------\n";

    choose = -1;
    while (choose != 0)
    {//函数调用
        cout << "请选择:";
        cin >> choose;
        switch (choose)
        {
        case 1://创建顺序表
            if (InitList(L))
                cout << "成功建立顺序表\n\n";
            else
                cout << "顺序表建立失败\n\n";
            break;
        case 2:   //构建顺序表
            if (CreatList(L))
                cout << "成功构建顺序表\n\n";
            else
                cout << "顺序表构建失败\n\n";
            break;
        case 3://顺序表长度
            cout << ListLength(L) << "\n\n";
            break;
        case 4://显示顺序表内容
            TraverseList(L);
            break;
        case 5://查找学生信息
            printf("请输入需要查找信息的学生姓名:\n");
            cin >> name;
            if (!LocateElem(L, name))
                cout << "查无此人\n\n";
            break;
        case 6: //获取学生信息
            printf("请输入需要获取信息的学生编号:\n");
            cin >> i;
            if (!GetElem(L, i))
                cout << "序号过大\n\n";
            break;
        case 7: //插入学生信息
            printf("请输入要插入学生的编号:\n");
            cin >> i;
            if (!ListInsert(L, i))
                cout << "序号太大插入失败\n\n";
            else
                cout << "插入成功\n\n";
            break;
        case 8://删除学生信息
            printf("请输入要删除学生的编号:\n");
            cin >> i;
            if (ListDelete(L, i))
                cout << "删除成功\n";
            else
                cout << "删除失败\n";
            break;
        case 9:  //销毁顺序表
            if (DestroyList(L)) cout << "成功删除顺序表\n\n";
            else   cout << "顺序表删除失败\n\n";
            break;
        }
        getchar();
    }
}

//1.初始化顺序表
Status  InitList(SqList& L)
{
    L.elem = new Student[MAXSIZE];
    if (!L.elem) exit(OVERFLOW);
    L.length = 0;
    return OK;
}

//2.创建顺序表
Status  CreatList(SqList& L)
{
    if (!L.elem)
        exit(OVERFLOW); //顺序表不存在退出
    do {
        printf("输入学号,姓名,成绩:\n");
        cin >> L.elem[L.length].no >> L.elem[L.length].name >> L.elem[L.length].grade;
        L.length++;
    } while (strcmp(L.elem[L.length - 1].name, "0") != 0);	//输入0 0 0时结束
    L.length--;
    if (L.length == 0)          //长度为0 初始时输入的no就是0 顺序表内无元素 创建失败
        return ERROR;
    return OK;
}

//3.遍历顺序表,显示顺序表内容
Status  TraverseList(SqList L)
{
    for (int i = 0;i < L.length;i++)
        cout << L.elem[i].no << ' ' << L.elem[i].name << ' ' << L.elem[i].grade << endl;
    cout << endl;
}

//4.查找(通过姓名)
Status  LocateElem(SqList L, char* name)
{
    for (int i = 0;i < L.length;i++)
        if (!strcmp(name, L.elem[i].name))
        {
            cout << L.elem[i].no << ' ' << L.elem[i].name << ' ' << L.elem[i].grade << endl << endl;
            return OK;
        }
    return ERROR;
}

//5.获取(通过序号)
Status  GetElem(SqList L, int i)
{
    if (i < L.length)
    {
        cout << L.elem[i].no << ' ' << L.elem[i].name << ' ' << L.elem[i].grade << endl << endl;
        return OK;
    }
    else
        return ERROR;
}

//6.插入(在指定位置i插入学生信息)
Status  ListInsert(SqList& L, int i)
{
    char no[8];
    char name[80];
    int grade;
    cin >> no >> name >> grade;
    if (0 <= i && i <= L.length)
    {
        for (int j = i + 1;j <= L.length;j++)
        {
            L.elem[j].grade = L.elem[j - 1].grade;
            strcpy(L.elem[j].name, L.elem[j - 1].name);
            strcpy(L.elem[j].no, L.elem[j - 1].no);
        }
        L.elem[i].grade = grade;
        strcpy(L.elem[i].name, name);
        strcpy(L.elem[i].no, no);
        L.length++;
        return OK;
    }
    else
        return false;
}

//7.删除(删除指定位置i的学生信息)
Status  ListDelete(SqList& L, int i)
{
    if (i >= 0 && i < L.length)
    {
        while (i < L.length - 1)
        {
            L.elem[i].grade = L.elem[i + 1].grade;
            strcpy(L.elem[i].name, L.elem[i + 1].name);
            strcpy(L.elem[i].no, L.elem[i + 1].no);
            i++;
        }
        L.length--;
        return OK;
        
    }
    else
        return ERROR;
}

//8.返回顺序表长度
int  ListLength(SqList L)
{
    return L.length;
}

//9. 销毁顺序表
Status  DestroyList(SqList& L)
{
    if (L.elem) delete[]L.elem;    //释放存储空间
    L.length = 0;
    return OK;
}

实验2 : 链表实现实验1

思路:

基本和实验1一样,只是加了文件读入。但是文件读入会莫名其妙读入错误数据,所以加了一个flag用来判断和使正常

代码:
#include<iostream>
#include<cstring>
#include<iomanip>
#include<fstream>

using namespace std;

#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;    //Status 是函数返回值类型,其值是函数结果状态代码。

typedef struct
{
    char no[80];		//学号
    char name[80];		//姓名
    int	 price;			//成绩
    
}Student;

typedef struct LNode
{
    Student data;		//结点的数据域
    struct LNode* next; //结点的指针域
} LNode, * LinkList;		//LinkList为指向结构体LNode的指针类型

typedef Student ElemType;  //ElemType 为可定义的数据类型,此设为Student类型
string head_1, head_2, head_3;//文件中的标题(第一行)
int  length;
bool flag = 0;
int main() {
    int a = 20;
    int i, choose, len;
    Student e;
    char name[80];
    LinkList L1 = NULL;
    //功能定义,声明函数

    Status InitList_L(LinkList & L);						//初使化链表
    void CreateList_H(LinkList & L, int n);					//前插法构建链表
    void CreateList_R(LinkList & L, int n);					//后插法构建链表
    int  ListLength_L(LinkList L);							//链表长度
    Status ListDisplay1(LinkList L);							//显示
    Status ListDisplay2(LinkList L);							//显示
    LNode* LocateElem_L(LinkList L, char* e);				//查找
    Status  GetElem_L(LinkList L, int i, Student & e);		//获取元素
    Status	ListInsert_L(LinkList & L, int i, Student & e);	//插入元素
    Status	ListDelete_L(LinkList & L, int i);				//删除
    Status  DestroyList_L(LinkList & L);						//销毁链表

    cout << "---------------------\n";
    cout << "1.初使化链表\n";
    cout << "2.前插法构建链表\n";
    cout << "3.后插法构建链表\n";
    cout << "4.求链表长度\n";
    cout << "5.显示链表内容\n";
    cout << "6.查找学生信息\n";
    cout << "7.获取学生信息\n";
    cout << "8.插入学生信息\n";
    cout << "9.删除学生信息\n";
    cout << "10.销毁链表\n";
    cout << "0.退出\n";
    cout << "---------------------\n";

    choose = -1;
    while (choose != 0)
    {
        cout << "\n\n请选择:";
        cin >> choose;
        switch (choose)
        {
        case 1: //初始化一个单链表
            if (InitList_L(L1))
                cout << "成功建立链表!\n";
            else
                cout << "建立链表失败!\n";
            break;

        case 2: //使用前插法创建单链表
            CreateList_H(L1, a);
            cout << "输入 students.txt 信息完毕(前插法)\n";
            break;

        case 3: //使用后插法创建单链表
            CreateList_R(L1, a);
            cout << "输入 students.txt 信息完毕(后插法)\n";
            break;

        case 4: //求单链表长度
            len = ListLength_L(L1);
            cout << "当前链表长度为:" << (flag ? len-2 : len-1) << "\n";
            break;

        case 5: //显示链表内容
            cout << "当前链表内容为:\n";
            if(flag){
            	ListDisplay1(L1);
			}else{
				ListDisplay2(L1);
			}
            break;

        case 6: //单链表的按序号取值
            cout << "请输入一个位置用来取值:";
            cin >> i;
            if (GetElem_L(L1, i, e))
            {
                cout << "查找成功\n";
                cout << "第" << i << "本学生证的信息是:\n";
                cout << e.no << "\t" << e.name << "\t" << e.price << endl;
                cout << endl;
            }
            else
                cout << "查找失败\n";
            break;

        case 7: //单链表的按值查找
            cout << "请输入所要查找学生姓名:";
            cin >> name;
            if (LocateElem_L(L1, name) != NULL)
            {
                e = LocateElem_L(L1, name)->data;
                cout << "查找成功\n";
                cout << "对应的学生信息为:\n" << e.no << "\t" << e.name << "\t" << e.price << "\n";
                cout << "补充语句" << endl;
            }
            else
                cout << "查找失败! " << name << " 没有找到\n";
            break;

        case 8: //单链表的插入
            cout << "请输入插入的位置和学生的信息(用空格隔开):";
            cin >> i;
            cin >> e.no >> e.name >> e.price;
            if (ListInsert_L(L1, i, e))	cout << "插入成功.\n";
            else	cout << "插入失败!\n";
            break;

        case 9: //单链表的删除
            cout << "请输入所要删除的学生的编号:";
            cin >> i;
            if (ListDelete_L(L1, i)) cout << "删除成功!\n";
            else	cout << "删除失败!\n";
            break;

        case 10: //销毁链表
            if (DestroyList_L(L1))
                cout << "成功销毁链表!\n";    break;
        }
    }
    return 0;
}
Status InitList_L(LinkList& L) { //构建
    L = new LNode; //生成新结点作为头结点,用头指针L指向头结点
    L->next = NULL; //头结点的指针域置空
    return OK;
}
void CreateList_H(LinkList& L, int n) {
    //逆位序输入 n 个元素的值,建立到头结点的单链表 L
    //补充语句
    LinkList p;
    L = new LNode;
    L->next = NULL; //先建立一个带头结点的空链表
    length = 0;
    fstream file; //定义文件指针 file
    file.open("date\\Student.txt"); //打开数据文件,Student.txt 必须放在与源程序同一文件夹下
    if (!file) { //判断文件是否存在
        cout << "未找到数据文件 Student.txt,无法打开!" << endl;
        exit(ERROR);
    }
    file >> head_1 >> head_2 >> head_3; //文件第一行:标题字符串
    char no0[80], name0[80];
    int price0;
    //	cout << head_1 << ' ' << head_2 << ' ' << head_3 << endl;
    while (file >> no0 >> name0 >> price0) { // 判断是否读完数据文件内容
        p = new LNode; //生成一个新结点,p 指向此结点
        //从文件中读入学生信息(学号、姓名和成绩)放入结点元素内
//        cout << no0 << ' ' << name0 << ' ' << price0 << endl;
        strcpy(p->data.no, no0); strcpy(p->data.name, name0);
        p->data.price = price0;
        p->next = L->next; //连接后结点(初始首元结点) L->next = p->next;
        L->next = p; //连接头结点(变成新的首元结点)
        length++; //同时对链表长度进行统计(长度加 1)}
    }
    file.close();
}
void CreateList_R(LinkList& L, int n) //后插法构建链表
{
    //补充语句
    L = new LNode;
    L->next = NULL; //先建立一个带头结点的空链表
    LinkList p, now = L;
    length = 0;
    flag = 1;
    fstream file; //定义文件指针 file
    file.open("date\\Student.txt"); //打开数据文件,Student.txt 必须放在与源程序同一文件夹下
    if (!file) { //判断文件是否存在
        cout << "未找到数据文件 Student.txt,无法打开!" << endl;
        exit(ERROR);
    }
    file >> head_1 >> head_2 >> head_3; //文件第一行:标题字符串
    while (!file.eof()) { // 判断是否读完数据文件内容
        p = new LNode; //生成一个新结点,p 指向此结点
        //从文件中读入学生信息(学号、姓名和成绩)放入结点元素内
        file >> p->data.no >> p->data.name >> p->data.price;
        p->next = NULL;
        now->next = p;
        now = p;
        length++; //同时对链表长度进行统计(长度加 1) }
    }
    file.close();
}
Status ListDisplay2(LinkList L)  //显示链表元素的内容
{
    LinkList p = L->next;
    for (int k = 1; k <= length; k++) {
        cout << p->data.no << '\t' << p->data.name << '\t' << p->data.price << endl;
        p = p->next;
    }
    return OK;
}
Status ListDisplay1(LinkList L)  //显示链表元素的内容
{
    LinkList p = L->next;
    for(int i = 1; i <= length-1; i++){
    	cout << p->data.no << '\t' << p->data.name << '\t' << p->data.price << endl;
        p = p->next;
	}
    return OK;
}

LNode* LocateElem_L(LinkList L, char* str) { //根据值(字串)查找
    LinkList p = L->next;
    while (p->next != NULL) {
        if (strcmp(p->data.name, str) == 0)
            return p;
        p = p->next;
    }
    return NULL;
}

Status GetElem_L(LinkList L, int i, Student& e) //根据序号查找
{
    LinkList p = L;
    if ((flag && i > length-1) || (!flag && i > length)) return ERROR;
    for (int j = 1; j <= i; j++)
        p = p->next;
    e = p->data;
    return OK;
}


Status ListInsert_L(LinkList& L, int i, Student& e) //插入一个结点 e 的内容
{
    LinkList p = L;
    if ((flag && i > length-1) || (!flag && i > length)) return ERROR;
    for (int j = 1; j <= i; j++) p = p->next;
    LinkList now = new LNode; now->data = e;
    now->next = p->next;
    p->next = now;
    length++;
    return OK;
}
Status ListDelete_L(LinkList& L, int i)  //删除
{
    if ((flag && i > length-1) || (!flag && i > length)) return ERROR;
    LinkList p = L;
    for (int j = 1; j <= i - 1; j++)  p = p->next;
    LinkList q = p->next;
    p->next = q->next;
    delete q; length--;
    return OK;
}
Status ListLength_L(LinkList L)//求链表长度
{
    int len = 0;
    while (L) {
        ++len;
        L = L->next;
    }
    return len;

}
Status DestroyList_L(LinkList& L) //销毁链表
{
    length = 0;
    LinkList p;
    while (L) {
        p = L;
        L = L->next;
        delete p;
    }
    return OK;
}


实验3:表达式求值

思路:

简单栈的模拟,遇到某个符号要做什么,写出来就行了。但是要注意的是输入的数不能超过9
简单描述一下思想,我们把所有的乘除运算算完后,就可以算加减。至于具体实现,只能说if else永远的神。我建议看的人不要直接拿,可以看看在for中是怎样处理的。

代码:
#include<bits/stdc++.h>
using namespace std;

char op[1000];
int op_size = 0;
double num[1000];
int num_size = 0;


void solve(string s) {
	op_size = 0; num_size = 0;
	int k = 0;
	while (s[k] == '(') k++, op[op_size++] = '(';
	num[num_size++] = s[k] - '0'; 
	for (int i = k+1; i < s.size() - 1; i++) {
		if (s[i] >= '0' && s[i] <= '9') {
			double x = s[i] - '0';
			if (op[op_size - 1] == '*' || op[op_size - 1] == '/') {
				double y = num[num_size - 1]; num_size--;
				char ch = op[op_size - 1]; op_size--;
				num[num_size++] = (ch == '*' ? x * y : 1.0 * y / x);
			}
			else {
				if(op[op_size-1] == '-'){
					x = -x;
					op[op_size-1] = '+';
				}
				num[num_size++] = x;
			}
			continue;
		}
		if (s[i] == '(') {
			op[op_size++] = '(';
			continue;
		}
		if (s[i] == ')') {
			while (op_size >= 1 && op[op_size - 1] != '(') {
				char ch = op[op_size - 1]; op_size--;
				double num1 = num[num_size - 1];  num_size--;
				double num2 = num[num_size - 1];  num_size--;
				num[num_size++] = (ch == '+' ? num1 + num2 : num2 - num1);
			}
			op_size--;
			double x = num[num_size-1]; num_size--;
			while(op_size >= 1 && (op[op_size-1] == '*' || op[op_size-1] == '/')){
				double y = num[num_size-1]; num_size--;
				char ch = op[op_size-1]; op_size--;
				x = (ch == '*' ? y * x : y/x);
			}
			num[num_size++] = x;
			continue;
		}
		op[op_size++] = s[i]; 
	}
	double ans = num[num_size - 1]; num_size--;
	while (op_size >= 1 && num_size >= 1) {
		char ch = op[op_size - 1]; op_size--;
		double num1 = num[num_size - 1]; num_size--;
		ans = (ch == '+' ? num1 + ans : num1 - ans);
	}
	cout << "计算结果为: " << ans << endl;
}

int main() {
	while (1) {
		cout << "---------------------------------" << endl;
		cout << "0-9 以内的多项式计算" << endl;
		cout << "1.计算" << endl;
		cout << "0.退出\n" << endl;
		cout << "选择:";
		int choose;
		cin >> choose;
		switch(choose) {
		    case 1 : 
			{
				cout << "请输入要计算的表达式(操作数和结果都在 0-9 的范围内,以#结束):" << endl;
				string s; cin >> s;
				solve(s);
			};
			break;
			case 0 :
			{
				cout << "退出成功\n";
				return 0;
			};
		}
	}
}

实验四:字符串匹配

思路:

暴力匹配和kmp。一个是一个一个找,一个是用前缀和后缀相等优化下一次找的过程,省去不必要找的地方。

代码:
#include<iostream>
#include<cstring>
using namespace std;

#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
#define MAX_STR_LEN 255						// 用户可在 255(1 个字节)以内定义最大串长
typedef char SString[MAX_STR_LEN + 1];		// 0 号单元存放串的长度

Status StrAssign(SString T, char* chars);

int StrLength(SString T);

void StrPrint(SString T);

bool Concat(SString T, SString S1, SString S2);

int Index_BF(SString S, SString T, int pos);

void get_next(SString T, int next[]);

int Index_KMP(SString S, SString T, int pos, int next[]);

void get_nextval(SString T, int nextval[]);


int main()
{
	int i, * next;
	char ch1[80], ch2[80];
	SString S1, S2, S, SUB;					// 定义串,第一个单元存储串的长度
	cout << "请输入第一个字符串:";
	cin >> ch1;
	StrAssign(S1, ch1);
	StrPrint(S1);

	cout << "请输入第二个字符串:";
	cin >> ch2;
	StrAssign(S2, ch2);
	StrPrint(S2);
	cout << "------------------------------------------------\n";
	cout << "第一个字符串长度为: " << StrLength(S1) << endl;
	cout << "第二个字符串长度为: " << StrLength(S2) << endl;

	cout << "\n============连接两个字符串构造主串==============\n";
	Concat(S, S1, S2); //用 S 返回 S1 和 S2 联接而成的新串
	cout << "主串长度为: " << StrLength(S) << endl;
	cout << "主串为: ";
	StrPrint(S);
	cout << "请输入子串:";
	cin >> ch2;
	StrAssign(SUB, ch2);
	cout << "子串长度为: " << StrLength(SUB) << endl;

	cout << "\n---------------BF 匹配算法及实现----------------\n";
	i = Index_BF(S, SUB, 1);			// 利用算法 4.6 求得串 s2 在 s1 中首次匹配的位置 i
	if (i)
		printf("主串和子串在第%d 个字符处首次匹配\n", i);
	else
		printf("主串和子串匹配不成功\n");

	cout << "\n---------------KMP 匹配算法及实现---------------\n";
	next = new int[StrLength(SUB) + 1];
	get_next(SUB, next);			// 利用算法 4.7,求得 next 数组,存于 next 中
	printf("子串的 next 数组为: ");
	for (i = 1; i <= StrLength(SUB); i++)
		cout << *(next + i);
	printf("\n");
	i = Index_KMP(S, SUB, 1, next);		// 利用算法 4.6 求得串 s2 在 s1 中首次匹配的位置
	if (i)
		printf("主串和子串在第%d 个字符处首次匹配\n", i);
	else
		printf("主串和子串匹配不成功\n");

	cout << "\n--------------KMP改进匹配算法及实现-------------\n";
	get_nextval(SUB, next);			    		// 利用算法 4.8,求得 next 数组,存于 next 中
	printf("子串的 nextval 数组为: ");
	for (i = 1; i <= StrLength(SUB); i++)
		cout << *(next + i);
	printf("\n");
	i = Index_KMP(S, SUB, 1, next);		// 利用算法 4.6 求得串 s2 在 s1 中首次匹配的位置 i
	if (i)
		printf("主串和子串在第%d 个字符处首次匹配\n", i);
	else
		printf("主串和子串匹配不成功\n");

	getchar();
	return 0;
}


Status StrAssign(SString T, char* chars) { //生成一个其值等于chars的串T
	int i;
	if (strlen(chars) > MAX_STR_LEN)
		return ERROR;
	else {
		T[0] = strlen(chars);				//第1个单元存放串的长度
		for (i = 1; i <= T[0]; i++)
			T[i] = chars[i - 1];
		return OK;
	}
}


void StrPrint(SString T)
{
	int i;
	for (i = 1; i <= T[0]; i++)
		cout << T[i];
	printf("\n");
}

int StrLength(SString T)
{
	return  T[0];
}


//用T返回S1和S2联接而成的新串,若未截断,则返回TRUE,否则返回FALSE
bool Concat(SString T, SString S1, SString S2)
{
	int t = 0;
	if (S1[0] + S2[0] <= MAX_STR_LEN)
	{ // 未截断
		for (int i = 1; i <= S1[0]; i++)
			T[++t] = S1[i];
		for (int i = 1; i <= S2[0]; i++)
			T[++t] = S2[i];
		T[0] = S1[0] + S2[0];
		return true;
	}
	else
	{ // 截断 S2
		for (int i = 1; i <= S1[0]; i++)
			T[t++] = S1[i];
		for (int i = 1; i <= MAX_STR_LEN - S1[0]; i++)
			T[t++] = S2[i];
		T[0] = MAX_STR_LEN;
		return false;
	}
}

//算法4.1 BF算法
int Index_BF(SString S, SString T, int pos)
{
	//返回模式T在主串S中第pos个字符之后第s一次出现的位置。若不存在,则返回值为0
	//其中,T非空,1≤pos≤StrLength(S)
	int i = pos;
	int j = 1;
	while (i <= S[0] && j <= T[0])
	{
		if (S[i] == T[j])
		{
			i++;
			j++;
		} //继续比较后继字符
		else
		{
			i = i - j + 2;
			j = 1;
		} //指针后退重新开始匹配
		if (j > T[0])
			return i - j + 1;
	}
	return 0;
}//Index


//算法4.3 计算next函数值
void get_next(SString T, int next[])
{ //求模式串T的next函数值并存入数组next
	int i = 1, j = 0;
	next[1] = 0;
	while (i < T[0])
		if (j == 0 || T[i] == T[j])
		{
			i++;
			j++;
			next[i] = j;
		}
		else
			j = next[j];
}//get_next

//算法4.2 KMP算法
int Index_KMP(SString S, SString T, int pos, int next[])
{ 	// 利用模式串T的next函数求T在主串S中第pos个字符之后的位置的KMP算法
	//其中,T非空,1≤pos≤StrLength(S)
	int i = pos, j = 1;
	while (i <= S[0] && j <= T[0])
	{
		if (S[i] == T[j] || j == 0)		// 继续比较后继字
		{
			i++;
			j++;
		}
		else
			j = next[j];				// 模式串向右移动
	}
	if (j > T[0])						// 匹配成功
		return i - j + 1;
	else
		return 0;
}//Index_KMP

//算法4.4 计算next函数修正值
void get_nextval(SString T, int nextval[])
{ // 求模式串T的next函数修正值并存入数组nextval
	int i = 1, j = 0;
	nextval[1] = 0;
	while (i < T[0])
		if (j == 0 || T[i] == T[j])
		{
			i++;
			j++;
			if (T[i] != T[j])
				nextval[i] = j;
			else
				nextval[i] = nextval[j];
		}
		else
			j = nextval[j];
}//get_nextval

实验5.二叉树

思路:

简单找就好

代码:
// 5.BiTree.cpp : 定义控制台应用程序的入口点。
//
/***********************二叉树综合运算******************************/
#include<iostream>
using namespace std;
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status;		// Status是函数的类型
typedef char TElemType;

//二叉链表定义
typedef struct BiNode {
	char data;
	struct BiNode* lchild, * rchild;
} BiTNode, * BiTree;

typedef BiTree QElemType;

//链队列的定义
typedef struct QNode {
	QElemType data;
	QNode* next;
}*QueuePtr;

typedef struct {
	QueuePtr front, rear; // 队头、队尾指针
} LinkQueue;


/***************以下为队列常用运算函数***************/
//初始化队列
Status InitQueue(LinkQueue& Q) {
	// 构造一个空队列Q
	Q.front = Q.rear = new QNode;
	Q.front->next = NULL;
	return OK;
}
//入队 算法3.17
Status EnQueue(LinkQueue& Q, QElemType e) {
	// 插入元素e为Q的新的队尾元素
	QNode* p = new QNode;
	p->data = e;
	p->next = NULL;
	Q.rear->next = p;  //将新结点插入队尾
	Q.rear = p;		   //修改队尾指针
	return OK;
}
//判断队空
Status QueueEmpty(LinkQueue Q) {
	// 若Q为空队列,则返回TRUE,否则返回FALSE
	if (Q.front->next == NULL)
		return TRUE;
	else
		return FALSE;
}
//出队
Status DeQueue(LinkQueue& Q, QElemType& e) {
	// 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR
	if (Q.front == Q.rear)
		return ERROR;
	QNode* p = Q.front->next;   //p指向队头指针
	e = p->data;
	Q.front->next = p->next;	//修改头指针
	if (Q.rear == p)
		Q.rear = Q.front;       //最后一个元素被删,队尾指针指向头结点
	delete p;
	return OK;
}

/***************以下为二叉树综合运算函数***************/
void InitBiTree(BiTree& T) {
	// 操作结果:构造空二叉树T
	T = NULL;
}

Status BiTreeEmpty(BiTree T) {
	// 初始条件:二叉树T存在。操作结果:若T为空二叉树,则返回TRUE,否则FALSE
	if (T)
		return FALSE;
	else
		return TRUE;
}

//销毁二叉树
void DestroyBiTree(BiTree T) {
	// 初始条件:二叉树T存在。操作结果:销毁二叉树T
	if (T) { // 非空树
		if (T->lchild) // 有左孩子
			DestroyBiTree(T->lchild); // 销毁左孩子子树
		if (T->rchild) // 有右孩子
			DestroyBiTree(T->rchild); // 销毁右孩子子树
		free(T); // 释放根结点
		T = NULL; // 空指针赋0
	}
}

//把指针指向给定元素
BiTree Point(BiTree T, TElemType s) {               //BFS
	// 返回二叉树T中指向元素值为s的结点的指针。另加
	LinkQueue q;
	BiTree a;
	if (T) { // 非空树
		InitQueue(q);  // 初始化队列
		EnQueue(q, T); // 根指针入队
		while (!QueueEmpty(q)) { // 队不空
			DeQueue(q, a); // 出队,队列元素赋给a
			if (a->data == s)
				return a;
			if (a->lchild) // 有左孩子
				EnQueue(q, a->lchild); // 入队左孩子
			if (a->rchild) // 有右孩子
				EnQueue(q, a->rchild); // 入队右孩子
		}
	}
	//  cout<<a->data<<endl;
	return NULL;
}

//给指定结点赋值
void Assign(BiTree p, TElemType value) {
	// 给p所指结点赋值为value
	p->data = value;
}
求某结果左孩子的值,如无则返回空
TElemType LeftChild(BiTree T, TElemType e) {
	// 初始条件:二叉树T存在,e是T中某个结点。操作结果:返回e的左孩子。若e无左孩子,则返回"空"
	BiTree a;
	if (T) { // 非空树
		a = Point(T, e);		// a是结点e的指针
		if (a && a->lchild)		// T中存在结点e且e存在左孩子
			return  a->lchild->data;	// 返回e的左孩子的值
	}
	return ' '; // 其余情况返回空
}

求某结果右孩子的值,如无则返回空
TElemType RightChild(BiTree T, TElemType e) {
	// 初始条件:二叉树T存在,e是T中某个结点。操作结果:返回e的右孩子。若e无右孩子,则返回"空"
	BiTree a;
	if (T) { // 非空树
		a = Point(T, e);		// a是结点e的指针
		if (a && a->rchild)		// T中存在结点e且e存在右孩子
			return a->rchild->data; // 返回e的右孩子的值
	}
	return ' '; // 其余情况返回空
}


利用队列求取某结点双亲的值,如找不能,则返回空
TElemType Parent(BiTree T, TElemType e) {               //BFS
	// 初始条件:二叉树T存在,e是T中某个结点
	// 操作结果:若e是T的非根结点,则返回它的双亲,否则返回"空"
	LinkQueue q;
	QElemType a; //BiTree a;
	if (T) { // 非空树
		InitQueue(q); // 初始化队列
		EnQueue(q, T);  // 树根指针入队
		while (!QueueEmpty(q)) { // 队不空
			DeQueue(q, a); // 出队,队列元素赋给a
			if (a->lchild && a->lchild->data == e || a->rchild && a->rchild->data == e) // 找到e(是其左或右孩子)
				return   a->data;  //返回e的双亲的值
			else { // 没找到e,则入队其左右孩子指针(如果非空)
				if (a->lchild)
					EnQueue(q, a->lchild);
				if (a->rchild)
					EnQueue(q, a->rchild);
			}
		}
	}
	return ' '; // 树空或没找到e
}

用算法5.3 先序遍历的顺序建立二叉链表
void  CreateBiTree(BiTree& T) {
	//按先序次序输入二叉树中结点的值(一个字符),创建二叉链表表示的二叉树T
	char ch;
	cin >> ch;
	if (ch == '#')  T = NULL;	//递归结束,建空树
	else {
		T = new BiTNode;
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}
用算法5.1 中序遍历
void InOrderTraverse(BiTree T) {
	//中序遍历二叉树T的递归算法
	if (T) {
		InOrderTraverse(T->lchild);
		cout << T->data << ' ';
		InOrderTraverse(T->rchild);
	}
}
先序遍历
void PreOrderTraverse(BiTree T) {
	//先序遍历二叉树T的递归算法
	if (T) {
		cout << T->data << ' ';
		PreOrderTraverse(T->lchild);
		PreOrderTraverse(T->rchild);
	}
}
后序遍历
void PostOrderTraverse(BiTree T) {
	//后序遍历二叉树T的递归算法
	if (T) {
		PostOrderTraverse(T->lchild);
		PostOrderTraverse(T->rchild);
		cout << T->data << ' ';
	}
}

//求树深度
int BiTreeDepth(BiTree T) {
	int m, n, depth;
	if (T == NULL) return 0; //如果是空树,深度为0,递归结束
	else {
		m = BiTreeDepth(T->lchild);
		n = BiTreeDepth(T->rchild);
		depth = max(m, n) + 1;
	}
	return depth;
}
//求叶子数 /
int LeafCount(BiTree T) {
	if (T == NULL)
		return 0;    //如果是空树,返回0
	if (T->lchild == NULL && T->rchild == NULL)
		return 1;    //如果是叶子结点,返回1
	else
		return LeafCount(T->lchild) + LeafCount(T->rchild);
}
求结点数/
int NodeCount(BiTree T) {
	if (T == NULL)
		return 0;
	else
		return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;
}
求根结点值//
TElemType Root(BiTree T) {
	if (T)
		return T->data;
	else return ' ';
}

int main() {
	BiTree T, p;
	TElemType e1, e2;
	int islelect;

	InitBiTree(T);
	cout << "------------------------------------------------------\n";
	printf("构造空二叉树后,树空否?%d(1:是 0:否)树的深度=%d\n", BiTreeEmpty(T), BiTreeDepth(T));
	e1 = Root(T);
	if (e1 != ' ')
		printf("二叉树的根为: %c\n", e1);
	else
		printf("树空,无根\n");
	cout << "------------------------------------------------------\n";

	printf("请先序输入二叉树(P121图5.10(b): ABC##DE#G##F###)\n");
	CreateBiTree(T);
	printf("建立二叉树后,树空否?%d(1:是 0:否)", BiTreeEmpty(T));

	e1 = Root(T);
	if (e1 != ' ')
		printf("二叉树的根为: %c\n", e1);
	else
		printf("树空,无根\n");
	cout << "------------------------------------------------------\n";
	cout << " 树的叶子数=" << LeafCount(T) << endl;
	cout << " 树的结点数=" << NodeCount(T) << endl;
	cout << " 树的叶深度=" << BiTreeDepth(T) << endl;

	printf("\n先序递归遍历二叉树:\n");
	PreOrderTraverse(T);
	printf("\n中序递归遍历二叉树:\n");
	InOrderTraverse(T);
	printf("\n后序递归遍历二叉树:\n");
	PostOrderTraverse(T);
	cout << "\n------------------------------------------------------\n";

	printf("\n请输入一个结点的值: ");
	cin >> e1;
	// cout<<e1;
	p = Point(T, e1); // p为e1的指针
	if (p)
		printf("结点的值为%c\n", p->data);
	else {
		cout << "输入结点值错误!请重新输入\n";
		cin >> e1;
		p = Point(T, e1);
		while(!p) {
			cout << "输入结点值错误!请重新输入\n";
			cin >> e1;
			p = Point(T, e1);
		}
	}
	cout << "\n------------------------------------------------------\n";

	printf("欲改变此结点的值,请输入新值: ");
	cin >> e2;
	Assign(p, e2);
	printf("\n先序递归遍历二叉树:");
	PreOrderTraverse(T);

	e1 = Parent(T, e2);
	if (e1 != ' ')
		printf("\n%c的双亲是%c", e2, e1);
	else
		printf("\n%c没有双亲\n", e2);

	e1 = LeftChild(T, e2);
	if (e1 != ' ')
		printf("\n%c的左孩子是%c\n", e2, e1);
	else
		printf("\n%c没有左孩子\n", e2);

	e1 = RightChild(T, e2);
	if (e1 != ' ')
		printf("\n%c的右孩子是%c\n", e2, e1);
	else
		printf("\n%c没有右孩子\n", e2);

	DestroyBiTree(T);
	return 0;
}


实验6:赫夫曼树

思路:

简单来说就是我们每次找两个最小的,然后一直维护就好
这里我偷了懒,直接STL优先队列淦上去,各位不要向我学习,建议自己再写一个找最小的函数。

代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int b[N];
map<int, string> mp;
struct vv {
	int w, id = 0;
	vv *date;
	vv* pa, * l, * r;
	bool operator<(const vv f)const { return f.w < w; }
	vv() {
		date = nullptr;
		pa = nullptr;
		l = nullptr;
		r = nullptr;
	} 
};
int n;
vv* root;

void build() {
	vv* node;
	priority_queue<vv> q;
	for (int i = 1; i <= n; i++) {
		node = new vv;
		cin >> node->w;
		b[i] = node->w;
		node->date = node;
		node->id = i;
		q.push(*node);
	}
	while (q.size() != 1) {
		node = new vv;
		auto x1 = q.top(); q.pop();
		auto x2 = q.top(); q.pop();
		node->w = x1.w + x2.w;
		node->l = x1.date, node->r = x2.date;
		(x1.date)->pa = node; 
		(x2.date)->pa = node;
		node->date = node;
		q.push(*node);
	}
	auto now = q.top(); q.pop();
	root = now.date;
}

void dfs(vv* to, string s) {
	if (to->l) dfs(to->l, s+'0');
	if (to->r) dfs(to->r, s+'1');
	if (!(to->l) && !(to->r)){
		mp[to->id] = s;
	}
}

int main() {
	cout << "输入叶子数" << endl; 
	cin >> n;
	cout << "输入叶子内容" << endl;
	build();
	dfs(root, "");
	for(int i = 1; i <= n; i++){
		cout << b[i] << ": " << mp[i] << endl;
	}
}

实验7.1邻接矩阵

代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int G[N][N];
bool vis[N];
int n, m;

//队列 
struct que{
	int quee[1000];
	int pre = 0, end = 0;
}; 

void push(que &x, int y){
	if(x.pre == 0){
		x.quee[++(x.pre)] = y;
	}
	x.quee[++(x.end)] = y;
}
void pop(que &x){
	x.pre++;
}
bool empty(que &x){
	if(x.pre > x.end) return 1;
	return 0;
}
int top(que &x){
	return x.quee[x.pre];
} 


void add(int u, int v, int w) {
	G[u][v] = G[v][u] = min(G[v][u], w);
}

void init(){
	for(int i = 1; i <= 100; i++){
		for(int j = 1; j <= 100; j++){
			G[i][j] = 10000;
		}
	}
}

//深度优先搜索
void dfs(int F[][110], int x) {
//	if(x > n) return;
	
	cout << x << ' ';
	vis[x] = 1;
	for (int i = 1; i <= n; i++) {
		if (F[x][i] != 10000 && !vis[i]) {
			vis[i] = 1;
			dfs(F, i);
		}
	}
}
//广度优先搜索
void bfs(int F[][110], int x){
	que q;
	push(q, x); 
	cout << x << ' ';
	vis[x] = 1;
	while(!empty(q)){
		int now = top(q); pop(q);
		for(int i = 1; i <= n; i++){
			if(F[now][i] != 10000 && !vis[i]){
				cout << i << ' ';
				vis[i] = 1;
				push(q, i);
			}
		}
	}
}


int main() {
	
	init();
	
	freopen("C:\\freopen\\input.txt", "r", stdin);
	cout << "2020131600226 李发展" << endl;
	cout << "输入点的个数,边的个数" << endl;
	cin >> n >> m;
	cout << n << ' ' << m << endl;
	for (int i = 1, u, v, w; i <= m; i++) {
		cout << "输入边的连接关系 u-(w)->v(表示u到v有一条为w的路径)\n";
		cin >> u >> v >> w;
		cout << u << ' ' << v << ' ' << w << endl;
		add(u, v, w);
	}
	int pos = 1;
	cout << "请输入起点 : ";
	cin >> pos;
	cout << pos << endl;
	cout << "\n深度优先搜索的结果是 " <<  endl;
	dfs(G, pos);
	memset(vis, 0, sizeof(vis));
	cout << "\n广度优先搜索的结果是 " << endl;
	bfs(G, pos);
}

实验7.2 邻接表

代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
bool vis[N];
//存图---------------------- 
struct node{
	int to, w;
	node *next = nullptr;
	node(){
		next = NULL;
	}
};
node head[N], *t;
void add(int from, int to, int w){
	t = new node();
	t->to = to;
	t->w = w;
	t->next = head[from].next;
	head[from].next = t;
}
//----------------------------
//队列---------------------
struct que{
	node quee[1010];
	int pre = 0, end = 0;
};
void push(que &x, node y){
	if(x.pre == 0){
		x.quee[++(x.pre)] = y;
	}
	x.quee[++(x.end)] = y;
}
void pop(que &x){
	x.pre++;
}
bool empty(que &x){
	if(x.pre > x.end) return 1;
	return 0;
}
node top(que &x){
	return x.quee[x.pre];
} 
//--------------

int n, m;

void dfs(int pos){
	cout << pos << ' ';
	vis[pos] = 1;
	for(node *now = head[pos].next; now != NULL; now = now->next){
		if(!vis[now->to]){
			vis[now->to] = 1;
			dfs(now->to);
		}
	}
}

void bfs(int pos){
	cout << pos << ' ';
	node tm = head[pos];
	que q;
	push(q, tm);
	vis[pos] = 1;
	while(!empty(q)){
		node now = top(q); pop(q);
		int to = now.to;
		node e = *(now.next);
		for(; e.next != NULL; e = *(e.next)){
			if(!vis[e.to]){
				vis[e.to] = 1;
				cout << e.to << ' ';
				push(q, head[e.to]);
			}
		}
		if(!vis[e.to]){
			if(!vis[e.to]){
				vis[e.to] = 1;
				cout << e.to << ' ';
				push(q, head[e.to]);
			}
		}
	}
}


int main(){
//	init();
	freopen("C:\\freopen\\input.txt", "r", stdin);
	cout << "请输入点的个数,边的个数" << endl; 
	cin >> n >> m;
	cout << n << ' ' << m << endl;
	for(int i = 1, u,v,w; i <= m; i++){
		cout << "输入边的连接关系 u-(w)->v(表示u到v有一条为w的路径)\n";
		cin >> u >> v >> w;
		cout << u << ' ' << v << ' ' << w << endl;
		add(u,v,w);
		add(v,u,w);
	}
	int pos;
	cout << "请输入起点 : ";
	cin >> pos;
	cout<< "\n深度优先搜索的结果是 : " << endl;
	dfs(pos);
	memset(vis, 0, sizeof(vis));
	cout << "\n广度优先搜索的结果是 : " << endl;
	bfs(pos);
}

实验8 最小生成树

代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
const int inf = 0x3f3f3f3f;
int G[N][N];
int n, m;

void add(int u, int v, int w){
	G[u][v] = G[v][u] = min(G[v][u], w);
}

int dist[N];
bool vis[N];

int prim(){
	for(int i = 1; i <= n; i++){
		dist[i] = inf;
		
	}
	for(int i = 2; i <= n; i ++){
		dist[i] = min(dist[i], G[1][i]);
	}
	dist[1] = 0;
	int ans = 0;
	for(int i = 1; i <= n; i++){
		int mn = inf, mn_idx = -1;
		for(int i = 1; i <= n; i++){
			if(mn > dist[i] && !vis[i]){
				mn = dist[i];
				mn_idx = i;
			}
		}
		if(mn_idx == -1){
			return -1;
		}
		vis[mn_idx] = 1;
		ans += mn;		
		for(int i = 1; i <= n; i++){
			if(!vis[i]){
				dist[i] = min(dist[i], G[mn_idx][i]);
			}
		}
		
		
	}
	
	return ans;
	
}

void init(){
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			G[i][j] = inf;
		}
	}
}

int main(){
	freopen("C:\\freopen\\input.txt", "r", stdin);
 	cout << "输入点的个数和边的个数" << endl; 
	cin >>  n >> m;
	cout << n << ' ' << m << endl;
	init();
	for(int i = 1, u, v, w; i <= m; i++){
		cout << "输入边的关系u, v, w表示u,v之间存在一条权值为w的路" << endl; 
		cin >> u >> v >> w;
		cout << u << ' ' << v << ' ' << w << endl; 
		add(u, v, w);
	}
	int ans = prim();
	
	cout << "普利姆算法最小生成树的结果是: " << ans << endl;
}

实验9 最短路

代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
const int inf = 0x3f3f3f3f;
int G[N][N];
int n, m;

void add(int u, int v, int w){
	G[u][v] = G[v][u] = min(G[v][u], w);
}

int dist[N];
bool vis[N];

void Dij(int pos){
	for(int i = 1; i <= n; i++){
		dist[i] = inf;
	}
	for(int i = 2; i <= n; i ++){
		dist[i] = min(dist[i], G[pos][i]);
	}
	dist[pos] = 0;
	for(int i = 1; i <= n; i++){
		int mn = inf, mn_idx = -1;
		for(int i = 1; i <= n; i++){
			if(mn > dist[i] && !vis[i]){
				mn = dist[i];
				mn_idx = i;
			}
		}
		if(mn_idx == -1){
			return ;
		}
		vis[mn_idx] = 1;
		for(int i = 1; i <= n; i++){
			if(!vis[i]){
				dist[i] = min(dist[i], G[mn_idx][i]+mn);
			}
		}
		
		
	}
	
}

void init(){
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			G[i][j] = inf;
		}
	}
}

int main(){
	freopen("C:\\freopen\\input.txt", "r", stdin);
 	cout << "输入点的个数和边的个数" << endl; 
	cin >>  n >> m;
	cout << n << ' ' << m << endl;
	init();
	for(int i = 1, u, v, w; i <= m; i++){
		cout << "输入边的关系u, v, w表示u,v之间存在一条权值为w的路" << endl; 
		cin >> u >> v >> w;
		cout << u << ' ' << v << ' ' << w << endl; 
		add(u, v, w);
	}
	cout << "输入出发点" << endl; 
	int pos;
	cin >> pos;
	Dij(pos);
	cout << "迪杰斯特拉算法最短路的结果是: ";
	for(int i = 1; i <= n; i++){
		cout << dist[i] << ' ';
	}
	cout << endl;
	
}

实验10 拓补排序与关键路径

思路:

简单来说拓补排序用入读是否为0来找,然后关键路径用拓补排序的思想找关键事件

代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int G[N][N], vl[N], ve[N];
void add(int u, int v, int w){
	G[u][v] = w;
}
int n, m;
int in[N];


bool tobu(){
	queue<int> q;
	for(int i = 1; i <= n; i++){
		if(in[i] == 0) q.push(i);
	}
	while(!q.empty()){
		int now = q.front(); q.pop();
		for(int i = 1; i <= n; i++){
			if(G[now][i] != 0){
				in[i]--;
			}
			if(in[i] == 0) q.push(i);
		}
	}
	for(int i = 1; i <= n; i++){
		if(in[i]) return 0;
	}
	return 1;
}

void get1(){
	memset(in, 0, sizeof(in));
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			if(G[i][j]) in[j]++;
		}
	}
}

void get2(){
	memset(in, 0, sizeof(in));
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			if(G[i][j]) in[i]++;
		}
	}
}

void dfs(int i, int j, string ans){
	if(j == n){
		cout << ans << endl;
		return;
	}
	for(int k = 1; k <= n; k++){
		if(k != i && G[j][k] != 0 && ve[k] == vl[k]){
			string tm = to_string(k);
			dfs(j, k, ans+"->"+tm);
		}
	}
}

void solve(){
	//找最早	//ve最早,vl最迟
	queue<int> q;
	get1();
	for(int i = 1; i <= n; i++) if(in[i] == 0) q.push(i);
	while(!q.empty()){
		int now = q.front(); q.pop();
		for(int i = 1; i <= n; i++){
			if(G[now][i] != 0){
//				printf("now = %d, i = %d, ve[%d] = %d, ve[%d] = %d, G[now][i] = %d\n", now, i, now, ve[now], i, ve[i], G[now][i]);
				ve[i] = max(max(0, ve[i]), ve[now] + G[now][i]);
				in[i]--;
				if(in[i] == 0) q.push(i); 
			}
		} 
	}
	
	get2();
	for(int i = 1; i <= n; i++){
		vl[i] = ve[n];
		if(in[i] == 0) q.push(i);
	}
	while(!q.empty()){
		int now = q.front(); q.pop();
		for(int i = 1; i <= n; i++){
			if(G[i][now]){
				vl[i] = min(vl[i], vl[now]-G[i][now]);
				in[i]--;
				if(in[i] == 0) q.push(i);
			}
		}
	}
	
	cout << "最早开始时间为 : ";
	for(int i = 1; i <= n; i++){
		cout << ve[i] << ' ';
	}
	cout << endl;
	cout << "最晚开始时间为 : ";
	for(int i = 1; i <= n; i++){
		cout << vl[i] << ' ';
	}
	cout << endl;
	dfs(0, 1, "1");
}


int main(){
	freopen("C:\\freopen\\input.txt", "r", stdin);
	//起点为1,终点为n 
	cin >> n >> m;
	for(int i = 1, u,v,w; i <= m; i++){
		cin >> u >> v >> w;
		add(u, v, w);
		in[v]++;
	}
//	for(int i = 1; i <= n; i++){
//		for(int j = 1; j <= n; j++){
//			cout << G[i][j] << ' ';
//		}
//		cout << endl;
//	}
	if(!tobu){
		cout << "图中存在环,无法进行拓补排序" << endl;
		return 0;
	}
	//vl最早,ve最迟
	solve();
}

实验11.查找

思路:

顺序找就是直接找, 带监视哨就是排序后把首元素为查找的值,用while找减少判断次数 二分直接把所有情况写好就好

代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 110;

struct vv{
	int num, id;
};

vv b[N];

void mysort(int len){
	for(int i = 1; i <= len; i++){
		int mn = 10000, mn_id = i;
		for(int j = i; j <= len; j++){
			if(mn > b[j].num){
				mn = b[j].num;
				mn_id = j;
			}
		}
		swap(b[i], b[mn_id]);
	}
}

void find1(int target, int len){
	for(int i = 1; i <= len; i++){
		if(b[i].num == target){
			cout << "找到元素"<< target << ",下标为" << b[i].id << endl;
			return;
		}
	}
	cout << "未找到元素" << endl;
}

void find2(int target, int len){
	int i = len;
	b[0].num = target;
	b[0].id = 0;
	while(b[i].num != target){
		i--;
	}
	if(i != 0){
		cout << "找到元素"<< target << ",下标为" << b[i].id << endl;
	}else{
		cout << "未找到元素" << endl;
	}
}

void find3(int target, int len){
	int l = 1, r = len;
	while(l < r){
		int mid = (l + r) / 2;
		if(b[mid].num == target){
			cout << "找到元素"<< target << ",下标为" << b[mid].id << endl;
			return;
		}else if(b[mid].num > target){
			r = mid-1;
		}else if(b[mid].num < target){
			l = mid+1;
		}
	} 
	cout << "为找到元素" << endl; 
}

int main(){
	int n;
	//静态查找
	cout << "静态查找" << endl;
	cout << "请输入数组长度 : ";
	cin >> n;
	cout << "请输入数组元素 : ";
	for(int i = 1; i <= n; i++) {
		cin >> b[i].num;
		b[i].id = i;
	}
	int target;
	cout << "请输入目标元素 : ";
	cin >> target;
	find1(target, n);
	
	//带监视哨的查找 
	cout << "带监视哨的查找 " << endl;
	cout << "请输入数组长度 : ";
	cin >> n;
	cout << "请输入数组元素 : ";
	for(int i = 1; i <= n; i++) {
		cin >> b[i].num;
		b[i].id = i;
	}
	target;
	cout << "请输入目标元素 : ";
	cin >> target;
	find2(target, n);
	
	//二分查找
	cout << "二分查找" << endl;
	cout << "请输入数组长度 : ";
	cin >> n;
	cout << "请输入数组元素 : ";
	for(int i = 1; i <= n; i++) {
		cin >> b[i].num;
		b[i].id = i;
	}
	mysort(n);
	cout << "请输入目标元素 : ";
	cin >> target;
	find3(target, n);
	
}

实验12

代码:
#include<bits/stdc++.h>
using namespace std;
#define ctx cout << "xxxxxxx" << endl
//-----------------------
//维护数据结构,二叉搜索数
//左子树比根节点小 ,右子树比根节点大

struct node {
	int data;
	node* l, * r;
	node() {
		l = nullptr;
		r = nullptr;
	}
};
node* head;
node *ans;

//查找
bool search(node* p, node* now, int tar) {
	if (now == NULL) {
		ans = p;
		return 0;
	}
	bool fg;
	if (now->data == tar) {
		ans = now;
		return 1;
	} else if (now->data > tar) {
		fg = search(now, now->l, tar);
	} else {
		fg = search(now, now->r, tar);
	}
	return fg;
	//	return 0;
}

//node *tm;
//更新
void updata(int x) {
	//找第一个比x大的数
	node *tm = new node();
	tm->data = x;
	if (head->l == nullptr) {
		head->l = tm;
		return;
	}
	bool flag = search(head, head->l, x);
	if (!flag) {
		if (ans->data > x) {
			ans->l = tm;
		} else {
			ans->r = tm;
		}
	}
}

//输出
void out(node* pre, node* now) {
	if (now == nullptr) return;
	out(now, now->l);
	cout << now->data << ' ';
	out(now, now->r);
}
//找pa
node *res;
void findpa(node *pre, node *now, int tar) {
	if(now->l != NULL && now->l->data == tar) {
		res = now;
		return;
	} else if(now->r != NULL && now->r->data == tar) {
		res = now;
	} else if(now->data > tar) {
		findpa(now, now->l, tar);
	} else if(now->data < tar) {
		findpa(now, now->r, tar);
	} else if(pre == head && now->data == tar) {
		res = pre;
		return;
	}
}

//删除
void del(int x) {
	node *p;
	bool flag = search(head, head->l, x);
	if(flag) {
		if(ans->l == NULL) { //左空
			findpa(head, head->l, x);
			if(res->l == ans) {
				res->l = ans->r;
			} else {
				res->r = ans->r;
			}
		} else if(ans->r == NULL) { //右空
			findpa(head, head->l, x);
			if(res->l == ans) {
				res->l = ans->l;
			} else {
				res->r = ans->l;
			}
		} else { //都有
			findpa(head, head->l, x);
			node *q = ans->l, *q2 = ans->l;
			while((q->r) != NULL) {
				if(q2 != q) q2 = q2->r;
				q = q->r;

			}
			node *q1 = q->l;
			if(q != ans->l) q->l = ans->l;
			if(q != ans->r) q->r = ans->r;
			if(q2 != q) q2->r = q1;
			if(res->l == ans) {
				res->l = q;
			} else {
				res->r = q;
			}
		}
		delete ans;
	} else {
		cout << "节点不存在" << endl;
	}
}

void myout() {
	out(head, head->l);
	cout << endl;
}

//----------------------------



int main() {
	head = new node();
	int op, x;
	while(1) {
		cout << "请输入操作 : 1.插入, 2.删除, 3.查找, 4.退出" << endl;
		cin >> op;
		int n, tm;
		if(op == 1) {
			cout << "请输入插入的个数 : " ;
			cin >> n;
			cout << "请输入插入的值 : " ; 
			for(int i = 1; i <= n; i++){
				cin >> x;
				updata(x);
			}
			
		}
		if(op == 2) {
			cout << "请输入删除的值 : " ;
			cin >> x;
			del(x);
		}
		if(op == 3) {
		    cout << "输入你要查找的值" ;
		    cin >> x;
		    bool flag = search(head, head->l, x);
		    if(flag){
		        cout << "找到该值" << endl;
		    }else{
		        cout << "该值不存在" << endl;
		    }
		}
		if(op == 4) break;
		myout();
	}
}

实验13,简单排序

思路:

没什么好说的,都是已经被前人想好的思想,就直接模拟

代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int b[110], n;

void out() {
	for(int i = 1; i <= n; i++) cout << b[i] << ' ';
	cout << endl;
}

//插入排序
void insert_sort() {
	cout << "输入数组数量 : ";
	cin >> n;
	while(n > 100) {
		cout<<"个数超过上限,不能超过"<<100<<",请重新输入"<<endl;
		cin>>n;
	}
	for(int i = 1; i <= n; i++) {
		int x;
		cin >> x;
		int j = 1;
		while(j <= i-1 && b[j] <= x) j++;
		for(int k = i; k >= j+1; k--) {
			b[k] = b[k-1];
		}
		b[j] = x;
	}
	out();
}

void binary_insert_sort() {
	cout << "输入数组数量 : ";
	cin >> n;
	while(n > 100) {
		cout<<"个数超过上限,不能超过"<<100<<",请重新输入"<<endl;
		cin>>n;
	}
	for(int i = 1; i <= n; i++) {
		int x;
		cin >> x;
		int l = 1, r = i;
		while(l < r) {
			int mid = (l + r) / 2;
			if(b[mid] <= x) {
				l = mid+1;
			} else {
				r = mid;
			}
		}
		for(int k = i; k >= l+1; k--) {
			b[k] = b[k-1];
		}
		b[l] = x;
	}
	out();
}

void shell_sort() {
	cout << "输入数组数量 : ";
	cin >> n;
	while(n > 100) {
		cout<<"个数超过上限,不能超过"<<100<<",请重新输入"<<endl;
		cin>>n;
	}
	for(int i = 1; i <= n; i++ ) cin >> b[i];
	for(int gap = n/2; gap > 0; gap /= 2) {
		for(int i=gap; i<=n; i++) {
			int j = i;
			while(j-gap>=0 && b[j]<b[j-gap]) {
				swap(b[j], b[j-gap]);
				j-=gap;
			}
		}
	}
	out();
}

void bubble_sort() {
	cout << "输入数组数量 : ";
	cin >> n;
	while(n > 100) {
		cout<<"个数超过上限,不能超过"<<100<<",请重新输入"<<endl;
		cin>>n;
	}
	for(int i = 1; i <= n; i ++) cin >> b[i];
	for(int i = 1; i <= n; i++) {
		for(int j = i+1; j <= n; j++) {
			if(b[i] > b[j]) swap(b[i], b[j]);
		}
	}
	out();
}

void qsort(int l, int r) {
	if(l >= r) return;
	int i = l, j = r, pos = l;
	while(i < j) {
		while(b[j] >= b[pos] && i < j) j--;
		while(b[i] <= b[pos] && i < j) i++;
		swap(b[i], b[j]);
	}
	swap(b[pos], b[j]);
	qsort(l, j-1);
	qsort(j+1,r);
}

void quick_sort() {
	cout << "输入数组数量 : ";
	cin >> n;
	while(n > 100) {
		cout<<"个数超过上限,不能超过"<<100<<",请重新输入"<<endl;
		cin>>n;
	}
	for(int i = 1; i <= n; i++) cin >> b[i];
	qsort(1, n);
	out();
}

void choose_sort() {
	cout << "输入数组数量 : ";
	cin >> n;
	while(n > 100) {
		cout<<"个数超过上限,不能超过"<<100<<",请重新输入"<<endl;
		cin>>n;
	}
	for(int i = 1; i <= n; i++) cin >> b[i];
	for(int i = 1; i <= n; i++) {
		int mn = 0x3f3f3f3f, mn_idx = i;
		for(int j = i + 1; j <= n; j++) {
			if(mn > b[j]) {
				mn = b[j];
				mn_idx = j;
			}
		}
		swap(b[i], b[mn_idx]);
	}
	out();
}

int main() {
	int op;
	while(1) {
		printf("=========================================\n");
		printf("1:直接插入法排序:\n");
		printf("2:折半插入法排序:\n");
		printf("3:希尔排序:\n");
		printf("4:冒泡法排序:\n");
		printf("5:快速排序:\n");
		printf("6:简单选择法排序:\n");
		printf("0:结束:\n");
		printf("=========================================\n");
		cout << "请选择:";
		cin >> op;
		if(op == 0) {
			cout << "退出成功" << endl;
			break;
		}
		switch(op) {
			case 1 : {
				insert_sort();
				break;
			}
			case 2 : {
				binary_insert_sort();
				break;
			}
			case 3: {
				shell_sort();
				break;
			}
			case 4: {
				bubble_sort();
				break;
			}
			case 5: {
				quick_sort();
				break;
			}
			case 6: {
				choose_sort();
				break;
			}
		}
	}
}

实验14 堆排序

思路:

我们维护数据结构堆,满足根节点的值是根与子节点中最小的。维护一个up, down操作,up是我们每次在堆的最后插入一个节点,然后去找根是否小于(大于)。down则是每次取数后把最后的值放在堆顶,然后向子节点找最小的,不断重复
思想都是前人弄好的,我们只管学了就用

代码:
#include<iostream>
using namespace std;
const int N = 1010;
int n, cnt;
int tree[N];

void up() {
	int idx = cnt/2, idx1 = cnt;
	while(idx > 0) {
		if(tree[idx] > tree[idx1]) swap(tree[idx], tree[idx1]);
		else {
			break;
		}
		idx /= 2;
		idx1 /= 2;
	}
}


void down() {
	int idx = 1;
	while(idx <= cnt) {
		int mn = 0x3f3f3f3f;
		if(2*idx <= cnt) {
			mn = min(tree[2*idx], mn);
		} else {
			break;
		}
		if(2*idx+1 <= cnt) {
			mn = min(tree[2*idx+1], mn);
		} else {
			if(tree[idx] > mn) {
				swap(tree[idx], tree[2*idx]);
			}
			break;
		}
		if(tree[idx] > mn) {
			if(tree[2*idx] > tree[2*idx+1]) {
				swap(tree[idx], tree[2*idx+1]);
				idx = 2*idx+1;
			} else {
				swap(tree[idx], tree[2*idx]);
				idx = 2*idx;
			}
		} else {
			break;
		}
	}
}

void insert(int x) {
	tree[++cnt] = x;
	up();
}

int mysize() {
	return cnt;
}

int top() {
	if(cnt)
		return tree[1];
}

void pop() {
	tree[1] = tree[cnt];
	cnt--;
	down();
}



int main() {
	cout << "数组数量 : ";
	cin >> n;
	for(int i = 1; i <= n; i++) {
		int x;
		cin >> x;
		insert(x);
	}

	for(int i = 1; i <= n; i++) {
		cout << top() << ' ';
		pop();
	}

}
+) {
		int mn = 0x3f3f3f3f, mn_idx = i;
		for(int j = i + 1; j <= n; j++) {
			if(mn > b[j]) {
				mn = b[j];
				mn_idx = j;
			}
		}
		swap(b[i], b[mn_idx]);
	}
	out();
}

int main() {
	int op;
	while(1) {
		printf("=========================================\n");
		printf("1:直接插入法排序:\n");
		printf("2:折半插入法排序:\n");
		printf("3:希尔排序:\n");
		printf("4:冒泡法排序:\n");
		printf("5:快速排序:\n");
		printf("6:简单选择法排序:\n");
		printf("0:结束:\n");
		printf("=========================================\n");
		cout << "请选择:";
		cin >> op;
		if(op == 0) {
			cout << "退出成功" << endl;
			break;
		}
		switch(op) {
			case 1 : {
				insert_sort();
				break;
			}
			case 2 : {
				binary_insert_sort();
				break;
			}
			case 3: {
				shell_sort();
				break;
			}
			case 4: {
				bubble_sort();
				break;
			}
			case 5: {
				quick_sort();
				break;
			}
			case 6: {
				choose_sort();
				break;
			}
		}
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
顺序存储的线性表 时数 2 性质 验证 内容:1、设线性表存放在向量A[arrsize]的前elenum个分量中,且递增有序。试设计一算法,将x插入到线性表的适当位置上,以保持线性表的有序性。 2、用向量作存储结构,试设计一个算法,仅用一个辅助结点,实现将线性表中的结点循环右移k位的运算。 3、用向量作存储结构,试设计一个算法,仅用一个辅助结点,实现将线性表逆置的运算。 要求:了解线性表的逻辑结构特征,熟练掌握线性表的顺序存储结构的描述方法,及在其上实现各种基本运算的方法。 单链表上的操作 时数 2 性质 验证 内容:1、已知带头结点的动态单链表L中的结点是按整数值递增排序的,试写一算法将值为x的结点插入到表L中,使L仍然有序。 2、设计一算法,逆置带头结点的动态链表L。要求利用原表的结点空间,并要求用尽可能少的时间完成。 3、假设有两个按元素值递增有序的线性表A和B,均以单链表作存储结构,试编写算法将A表和B表归并成一个按元素值递减有序的线性表C,并要求利用原表的空间存放C。 要求:熟练掌握线性表的单链式链接存储结构及在其上实现线性表的各种基本运算的方法。 循环链表和双链表 时数 2 性质 验证 内容:1、假设在长度大于1的单循环链表中,既无头结点也无头指针。s为指向某个结点的指针,试编写算法删除结点*s的直接前驱结点。 2、已知由单链表表示的线性表中,含有三类字符的数据元素(如:字母、数字和其它字符),设计算法构造三个以循环链表示的线性表,使每一个表中只含同一类的字符,且利用原表中的结点空间作为这三个表的空间。(头结点可以另辟空间) 3、有一双链表,每个结点中除有prior、data和next域外,还有一访问频度域freq,在链表被启用前,其值均初始化为零。每当在链表上进行一次LOCATE(L,x)运算,元素值为x的结点中freq域的值增1,并使此链表中结点保持按freq递减的顺序排列,以便使频繁访问的结点总是靠近表头。设计满足上述要求的LOCATE算法。 要求:熟练掌握线性表的循环链式和双链式链接存储结构及在其上实现线性表的各种基本运算的方法。 栈和队列 时数 2 性质 验证 内容:1、设单链表中存放着n个字符,设计算法,判断该字符串中是否有中心对称关系。例如:xyzzyx、xyzyx都算是中心对称的字符串。 2、设计算法判断一个算术表达式的圆括号是否配对。(提示:对表达式进行扫描,遇‘(’进栈,遇‘)’退掉栈顶的‘(’,表达式被扫描完毕,栈为空) 3、假设以带头结点的循环链表表示队列,并只设一个指针指向队尾,编写相应的置队空、入队和出队算法。 要求:掌握栈和队列的数据结构的特点;熟练掌握在两种存储结构上实现栈和队列的基本运算;学会利用栈和队列解决一些实际问题。 串运算的实现 时数 2 性质 验证 内容:1、若X和Y是用结点大小为1的单链表表示的串,设计算法找出X中第一个不在Y中出现的字符。 2、设计一算法,在顺序串上实现串的比较运算strcmp(S,T)。 3、若S和T是用结点大小为1的单链表存储的两个串,设计算法将S中首次与T匹配的子串逆置。 要求:熟练掌握串的顺序和链接存储结构的实现方法;熟练掌握在两种存储结构上实现串的各种运算。 树的应用 时数 2 性质 验证 内容:1、以二叉链表作存储结构,设计求二叉树高度的算法。 2、一棵n个结点的完全二叉树用向量作存储结构,用非递归算法实现对该二叉树进行前序遍历。 3、以二叉链表作存储结构,编写非递归的前序、中序、后序遍历算法。 要求:熟悉二叉树的各种存储结构的特点及适用范围;掌握建立二叉树的存储结构的方法;熟练掌握二叉树的前序、中序、后序遍历的递归及非递归算法;灵活运用递归的遍历算法实现二叉树的其它各种运算。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值