数据结构填坑

痞子三分冷 提交于 2020-01-12 04:22:17


把之前立下的flag补完,太懒了,有好多好多东西没写。

小战士过火线

	/**
* 通过逆操作来复原
* 
* 因为要进行尾删除和头插入操作,所以采取链表来来存储
*/

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

/* 存储战士信息 */
typedef struct node
{
   int value; //1代表老战士,2代表新战士
   struct node *next;
} NODE;
typedef NODE *List;

List init();                     //初始化队列
int deleteLastNode(List L);      //删除并返回最后在一个值
void addNode(List L, int value); //在对头添加一个节点
void printAns(List L);           //打印结果

int main()
{
   List L = init();
   for (int i = 0; i < 4; i++)
   {
       addNode(L,deleteLastNode(L)); //把最后一个节点移动到开头
       addNode(L,0); //先是小战士
       addNode(L,1); //再是老战士
   }
   printAns(L);

   return 0;
}


List init()                     //初始化队列
{
   /* 申请一个头节点 */
   List L = (List)malloc(sizeof(NODE));
   L->next = NULL;
   L->value = -1;
   /* 加入101 */
   addNode(L,1);
   addNode(L,0);
   addNode(L,1);
   
   return L;
}
int deleteLastNode(List L)      //删除并返回最后在一个值
{
   List p = L;
   /* 找到队尾 */
   while (p->next->next != NULL) //这里链表至少要有俩个节点
   {
       p = p->next;
   }
   List q = p->next;
   int tmp = q->value; //保存返回值
   p->next = q->next;
   free(q);

   return tmp;
}
void addNode(List L, int value) //在对头添加一个节点
{
   List p = (List)malloc(sizeof(NODE));
   p->value = value;
   p->next = L->next;
   L->next = p;
}
void printAns(List L)           //打印结果
{
   L = L->next;
   while(L)
   {
       printf("%d",L->value);
       L = L->next;
   }
}

静态链表

/**
 * 静态链表相比较于普通的链表可以减少 malloc的操作
 * 但是也需要事先知道大小,顺序表的特点
 * 可以比较快速的实现插入和删除的操作,链式表的特点
 * 
 * 适合那些已知最大数据量的表
 *  ps:它能做到的,链表都能做到
 * 
 * 0是空的链表池
 * 1是头节点
 */

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

typedef struct node
{
    int value; //数据
    int next;  //下一个
} NODE;
typedef NODE *List;

List init(int size);                //根据大小初始化
void addNode(List L, int value);    //添加元素
void deleteNode(List L, int value); //删除元素
int  isFull(List L);                //是否满了
void printList(List L);             //打印

int main()
{
    List L = init(20);
    char op;
    int value;
    //测试
    // for(int i=1;i<22;i++)
    // {
    // 	addNode(L,i);
	// }
	// printList(L);
	// for(int i=5;i<15;i++)
	// {
	// 	deleteNode(L,i);
	// }
    // printList(L);
    //  for(int i=1;i<22;i++)
    // {
    // 	addNode(L,i);
	// }
	// printList(L);
    
    /* 测试 */
    while (op = getchar(), op != 'q')
    {
        switch (op)
        {
            case 'a':
            {
                scanf("%d",&value);
                getchar();//读取回车
                addNode(L,value);
            };break;
            case 'd':
            {
                scanf("%d",&value);
                getchar();//读取回车
                deleteNode(L,value);
            };break;
            case 'p':
            {
                getchar();//读取回车
                printList(L);
            };break;
            case 'f':
            {
                getchar();//读取回车
                printf("is full?%s\n",isFull(L)?"yess":"no");
            };break;

            default:
                break;
        }
    }

    return 0;
}

List init(int size)               //根据大小初始化
{
    List L = (List)malloc(sizeof(NODE)*(size+2));//俩个头节点
    L[1].next = L[size+1].next = 0;//0作为终止标识
    L[0].next = 2;
    for(int i=2;i<size+1;i++)
    {
        L[i].next = i+1;
    }

    return L;
}
void addNode(List L, int value)    //添加元素
{
    /* 检查是不是满了 */
    if(isFull(L))
    {
        printf("已经满了,插入失败\n");
        return;
    }
    /* 插入操作 */
    /* 取空的节点 */
    int p = L[0].next;
    L[0].next = L[p].next;
    /* 在头部插入 */
    L[p].value = value;
    L[p].next = L[1].next;
    L[1].next = p;
}
void deleteNode(List L, int value) //删除元素
{
    /* 指向要删除的元素 */
    int p = 1;
    while (L[p].next != 0 && L[L[p].next].value != value )
    {
        p = L[p].next;
    }
    /* 没找到 */
    if(L[p].next == 0)
        return;
    /* 删除操作 */
    int q = L[p].next;
    L[p].next = L[q].next;
    L[q].next = L[0].next;
    L[0].next = q;
}
int  isFull(List L)               //是否满了
{
    return L[0].next == 0;
}
void printList(List L)            //打印
{
    int p = L[1].next;
    while (p)
    {
        printf("%d  ",L[p].value);
        p = L[p].next;
    }
    putchar('\n');
}

打印字符串

/**
 * 利用类似于深度优先的方法打印所有的字符串
 * 
 *  1.启发函数,来调动,按顺序选取第一个值,加标记
 *  2.在剩下的值里面挑选,知道长度符合要求
 *
 * @2020/1/09
 * 果然憨憨遇到的都是憨憨
 */

#include <stdio.h>

/* 全局变量 */
int  visited[26];//标记是不是访问过了
char curAns[27];
int  cnt;//检查是否正确  注意:这里的输出是字母只使用一次的 不存在aaa这种,
				//长度为3的所有组合为 26 + 26*25 + 26*25*24 

void slove(int maxLenth);//启动函数
void DFS(int curLenth,int endLenth);//深度搜索
void printAns();//打印

int main()
{
    int maxLenth;
    scanf("%d",&maxLenth);
    slove(maxLenth);
	
	printf("cnt: %d\n",cnt);
    return 0;
}

void slove(int maxLenth)//启动函数
{
    for(int i=1;i<=maxLenth;i++)
    {
        for(int j=0;j<26;j++)
        {
            visited[j] = 1;
            curAns[0] = j + 'a';
            DFS(1,i);
            visited[j] = 0;
        }
    }
}
void DFS(int curLenth,int endLenth)//深度搜索
{
    /* 是否已经达到目标 */
    if(curLenth == endLenth) //退出
    {
        curAns[endLenth] = '\0';
        printAns();
        return;
    }
    for(int i=0;i<26;i++)
    {
        if(!visited[i]) //没有被访问
        {
            visited[i] = 1;
            curAns[curLenth] = i + 'a';
            DFS(curLenth+1,endLenth);
            visited[i] = 0;
        }
    }
}
void printAns()//打印
{
    puts(curAns);
    cnt++; 
}

出栈顺序

/**
 * 有好多种思路,采用比较好接受的俩种
 * 
 * 1.模拟
 *      1.创建一个栈
 *      2.初始化(压栈到栈顶是当前的元素)
 *      3.出栈
 *      4.检查栈顶是不是要出栈的元素
 *          如果是,到3
 *          如果不是,那么判断是不是可以压栈到达
 *                可以压栈,到3
 *                不可以,那么退出
 * 2.逻辑检测
 *      就是一个出栈顺序abcde,a后面小于a的值一定要符合逆序
 *
 * @2020/1/9
 * ps:大一的妹纸果然比我认真多了
 */

#include <stdio.h>
#include <stdlib.h>
#define MAX_N 1000 //判断的大小

int slove1(int array[],int n);//第一种方法
int slove2(int array[],int n);//第二种方法

int main()
{
    /* 获取输入 */
    int n;
    while (scanf("%d",&n),n>0)
    {
        int* array = (int*) malloc(sizeof(int)*n);
        for(int i=0;i<n;i++)
            scanf("%d",&array[i]);
        printf("1:isOk?%s \n",slove1(array,n)?"yes":"no");
        printf("2:isOk?%s \n",slove2(array,n)?"yes":"no");
        
        free(array); //多次重复,所以写一个释放
    }
    

    return 0;
}

int slove1(int array[],int n)//第一种方法
{
    int stack[MAX_N];
    int tail = 0;//指向栈顶的下一个
    int max = 1;
    for(int i=0;i<n;i++) //要出栈n次
    {
        while(tail==0 || stack[tail-1] != array[i]) //不符合出栈的需要
        {
            if(max > array[i])//入栈的值大于需要入栈的值
                return 0;
            else
                stack[tail++] = max++;
        }
        tail--;//出栈
    }

    return 1;
}
int slove2(int array[],int n)//第二种方法
{
    int max = 0;
    for(int i=0;i<n;i++)
    {
        if(array[i] < max && array[i]>array[i-1])
            return 0;
        max = max > array[i]?max:array[i];    
    }

    return 1;
}


图的基本操作

/**
 * 先插眼,写下思路,以后再补充吧。
 * 
 * 1.图的存储结构
 *      a.矩阵存储,比较奢侈,适合边特别多的情况,以及数据量小的情况(不必考虑效率)
 *      b.邻接表,较好实现,不易出错
 *      c.十字链表,效率高,但是不太好写
 * 
 * 2.拓扑排序
 *      辅助数组存储各个几点的入度
 *      辅助栈
 *      1.统计各个节点的入度
 *      2.将入度为0的节点压栈
 *      3.挑一个入度为0的节点输出,并改变其进入的节点的入度,若为0,压栈
 *      4.重复3,直达栈空(如果有环的话,栈空了,但是打印的节点数不够)
 * 
 * 3.反转 
 *      比较简单的是重新开一个G,然后添加
 * 
 * 4.最小生成树
 *      Prime: 
 *              将节点分为俩类,一类是已入树的(A),一类是未入树的(B)
 *              辅助数组记录B种节点与A的距离
 *              1.随便取一个点x,入A
 *              2.改变B中与x有关的节点的距离
 *              3.挑选辅助数组里距离最近的点,(看起来得用一个优先队列),入A,重复2,直到B空
 *      
 *      Fraskal:
 *              辅助数组记录边的距离
 *              1.挑选最短的边,得到俩个相关节点a,b
 *              2.判断a,b是不是连通
 *                  如果是,重复1
 *                  如果不是,将a,b所对应的图链接(并查集),重复1
 * 
 * 4.最短路径
 *       Dijstra: 
 *              辅助数组记录v到该点的最短距离
 *              1.挑一个最短的距离,找到对应点a
 *              2.判断a是否已经连通
 *                      如果是,重复1
 *                       如果不是,那么将a连入,更新与a有关的点的距离,重复1,直到遇到要求的点
 *
 *        Floyd:
 *              dp[i][j] 从i到j的最短距离
 *              for(插入点k)
 *                  for (起始点x)
 *                      for (终止点y)
 *                          插入点k是否能使x到y的距离变小 
 *                              ps:为了防止溢出,先判断一下是不是联通
 *                          dis = dp[i][k] == MAX || dp[k][j] == MAX ? MAX: dp[i][k] + dp[k][y];
 *                          dp[i][j] = dp[i][j] < dis ? dp[i][j]:dis;
 * 
 *                              
 *              
 * 
 * 5.求关键路径
 *      准备:
 *          a.拓扑序
 *          b.反转
 *      1.求最早开始时间 t1
 *      2.求最晚开始时间 t2
 *      3.时间 t3 = 最晚开始时间 - 工作所需时间
 *      4. t1 == t3 的点就是关键路径上的点
 * 
 * 6.求关节点,这个太玄乎了,还没搞懂
 *
 * @2020/1/10
 * 打了鸡血补上代码
 */

一笔画求解

/**
 * 对于这种试验型的问题,其实大多数靠直觉和运气,去年回家小侄女老是要我帮她做这个
 * 开始还行,后来就越来越玄乎了,今年回家前写一个,让她看看我的厉害,啧啧啧
 * 
 * 为了方便,利用矩阵存储,对于某些问题需要经过俩次的,可以 G[i][j] = n 
 * 
 * @2020/1/10
 * 先写个思路,明天实现
 * 1.建立图,输入 x y (n) 如过没有n 那么默认是1,这个倒是可以利用getchar 判断是空格是不是来实现
 *      记录一下边的数目
 * 3.拷贝图
 * 2.对每一个节点开始DFS,走过一次边,就-1,直到没有边可走,判断是不是走了所有的边(利用边的数目)
 * 
 * 
 */

#include <stdio.h>
#define MAX_N 20 //20个节点

/* 全局变量 */
int gPre[MAX_N][MAX_N]; //保存最开始的输入
int gCur[MAX_N][MAX_N]; //保存当前的结果
int totalE; //总边数,用来判断是不是走完了
int totalV; //总的节点数
int path[MAX_N * 2]; //记录路径,这里×2考虑到有些是要走俩次的
int pathLenth; //指向路径尾


void getInfo();//获取输入,返回一下节点数目
void initInfo();//初始化数据
int  DFS(int x,int deep);//搜索
void printPath();//打印路径

int main()
{
    while(1)
    {
    	int flag=0;
    	getInfo();
    	for(int i=0;i<totalV;i++)
    	{
        	initInfo();
        	path[0] = i;
        	pathLenth = 1;
        	if(DFS(i,1))
        	{
        		printPath();
        		flag = 1;
        		break;//只打印一种 
			}
   		}
    	if(!flag) 
			printf("生成失败是不是,输入出错了啊?\n"); 
	}
	
    return 0;
}

void getInfo()//获取输入,返回一下节点数目
{
    printf("请输入节点数: ");
    scanf("%d",&totalV);
    printf("请输入边x y (数目如果不输入,默认为1)  (-1 -1 表示结束): \n");
    int x,y,time;
    while (scanf("%d %d",&x,&y),x!=-1)
    {
        time = 1;
        totalE++; //边数增加
        char c = getchar();
        if(c != '\n')
            scanf("%d",&time);
        gPre[x][y] = time;
        gPre[y][x] = time; //无向图 
    }
}
void initInfo()//初始化数据
{
    /* 清空路径 */
    pathLenth = 1;
    /* 拷贝图 */
    for(int i=0;i<totalV;i++)
        for(int j=0;j<totalV;j++)
            gCur[i][j] = gPre[i][j];
}
int  DFS(int x,int deep)//搜索
{
    /* 判断是不是能退出了 */
    if(deep-1 == totalE)
        return 1;
    /* 找x节点能走的部分 */
    for(int i=0;i<totalV;i++)
    {
        if(gCur[x][i])
        {
            gCur[x][i]--;
            gCur[i][x]--;
            path[pathLenth++] = i;
            if(DFS(i,deep+1))
                return 1;
            gCur[x][i]++;
            gCur[i][x]++;
            
            pathLenth--; 
        }
    }

    return 0;
}
void printPath()//打印路径
{
	printf("\n\n可能行的一条路径为: ");
    for(int i=0;i<pathLenth;i++)
        printf("%d  ",path[i]);
    putchar('\n');
}

原地归并排序

/** 
 * 原地归并的O(1)空间复杂度实现,其实是O(logn)
 * 
 * yw念念叨叨了一个学期的东西,啧啧啧,总算是搞懂是啥了
 * 
 * 利用了翻转:
 *      123456->561234
 *          1.1234->4321 56->65 --> 432165
 *          2.432165 -> 561234
 *  1.先递归拆分,直到1
 *  2.合并
 *  3.找前段,找后段
 * 
 * 
 * @2020/1/11
 */


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

void swap(int array[],int a,int b);//交换俩个数
void reverse(int array[],int l,int r);//反转
void convert(int array[],int l,int m,int r);//反转
void merge(int array[],int l,int m,int r);//合并
void mergeSort(int array[],int l,int r);//合并排序启发


//int array[10];
int main()
{
    /* 输入 */
    int n;
    scanf("%d",&n);
    int* array = (int*) malloc (sizeof(int)*n);
    for(int i=0;i<n;i++)
        scanf("%d",&array[i]);
    /* 合并 */
    mergeSort(array,0,n-1);
    /* 打印 */
    for(int i=0;i<n;i++)
        printf("%d ",array[i]);
    putchar('\n');

    return 0;
}

void swap(int array[],int a,int b)//交换俩个数
{
    array[a] ^= array[b];
    array[b] ^= array[a];
    array[a] ^= array[b];
}
void reverse(int array[],int l,int r)//反转
{
    while (l<r)
    {
    	swap(array,l++,r--);
//    	printf("ok %d %d\n",l,r);
	}
}
void convert(int array[],int l,int m,int r)//反转,从m起
{
    reverse(array,l,m-1);
    reverse(array,m,r);
    reverse(array,l,r);
}
void merge(int array[],int l,int m,int r)//合并,这个函数极容易出错
{
    int i = l;
    int j = m+1;
    while (i<j && j<=r)
    {
        while (array[i] < array[j] && i<j)
            i++;
        if(i==j) //第一处
        	break;
        int index = j;
        while(j<=r && array[j] <= array[i])//第二处
            j++;
        convert(array,i,index,j-1);
        i += j-index;
    }
}
void mergeSort(int array[],int l,int r)//合并排序启发
{
    if(l<r)
    {
        mergeSort(array,l,(l+r)>>1);
        mergeSort(array,(l+r)/2+1,r);
        merge(array,l,(l+r)/2,r);
    }
}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!