精华内容
下载资源
问答
  • ——个人笔记 这对于初学C的人来说,是一个比较有意思的问题。要运用到的知识点比较全面,方法也比较实用 思路 这个只是个人思路,如果你想到更好的...直接sizeof(array)/sizeof(array[0])是获取到这个数组的容...

    ——个人笔记

    • 这对于初学C的人来说,是一个比较有意思的问题。要运用到的知识点比较全面,方法也比较实用

    数组思路

    • 这个只是个人思路,如果你想到更好的不妨试试。首先由于C没有动态数组,那么我们就声明一个int类型范围比较大的数组,比如 int array[1000]。那么我们要知道里面存放多少个元素,要怎么获取呢?直接用sizeof(array)/sizeof(array[0])是获取到这个数组的容量大小,而不是元素多少。那么我们要有一个标记,记录当前元素的个数(声明int len=0;)。添加就是我们要添加一个元素,就把array[len]=该元素,然后len++就实现了添加功能。删除就是查找数组(遍历数组)找到与要删除相同的元素那么就删除而且len--输出就是循环i从0开始,到i<len输出就行了。要实现一直能输入,只要把我们做好的功能放到一个死循环进行就可以了。

    数组实现

    • 上面的思路懂了,可能还是一脸懵逼不知道怎么写。
      那么从最简单的入手,先定义我们需要的变量

      int array[1000] = { 0 };//我们要用的数组
      int len = 0;//标记,记录当前元素个数
      int choice;//我们要进行的操作
      int input;//输入增加或者删除的元素
      
      //这个是阐述这个编程的功能按键,放在这里是不想再下面写那么多。
      printf("请输入你要的操作\n--1--添加元素\n--2--删除元素\n--3--输出元素和有多少元素\n--4--退出程序\n");
      
    • 如果一开始漏了一些需要用到的变量的定义也无所谓,我们在实现的时候再补上就行。
      开始编写内容:

    • 要可以选择多种操作,我们可以想到分支(switch)那么我们就有一个整体框架了(退出操作要在死循环才要处理,比如输入4结束(while(1){if(choice==4)break;})或者在case 4:return;也行)

      switch (choice)
      		{
      		case 1:
      			printf("请输入要添加的元素:\n");
      			 //TODO 要进行添加操作
      		case 2:
      			printf("请输入要删除的元素:\n");
      			//TODO进行删除操作
      			break;
      		case 3:
      			printf("数组总共有%d个元素:\n", len);
      			//这里我就不详细讲了,查询操作
      			for (int i = 0; i < len; i++)
      			{
      				printf("%d ", array[i]);
      			}
      			printf("\n");
      			break;		 
      		default:
      			break;
      		}		 
      
    • 理解后,我们只要补充TODO的部分就行了
      添加元素:

      //放在cese 1下面
      scanf("%d", &input);
      array[len] = input;
      len++;
      
    • 删除元素:

      //放在case 2下面
      scanf("%d", &input);
      for (int i = 0; i < len; i++)
      {
      	if (array[i] == input)//检测到是要删除的元素
      	{
      		for(int j=i;j<len-1;j++)//把数组前移,覆盖了要删除的元素
      		{
      			array[j] = array[j + 1];
      		}
      		len--;//标记前移,相当于删除了最后一个位置
      		i--;//这个为什么要减呢?别急,下面会讲,先懂得上面数组和标记前移为啥能删除元素
      	}
      }
      printf("\n");
      

      上面为什么检测到要删除的元素,删除之后,需要把i也减去1呢?你可以看到大循环里面,我们结束条件是i<len,但是删除元素的时候(里面的循环)len会–,而我们当前检测到的位置已经变成了后面的元素了,所以要重新检测当前位置。你可以尝试一下不要i--;这一句,一般情况下还是正确的,只是如果出现连续相同的元素那么你就会出错,比如你连续添加了6个1,现在你按3输出数组,那么是1 1 1 1 1 1,然后你删除元素1,会怎么?再加上i--;,再运行试一下。你自己模拟一下你是计算机,用纸笔模拟一下哈哈!不理解再想想,完整代码应该不需要了吧,不懂再问!

    指针思想

    • 虽然C没有动态数组,但是我们可以申请连续的空间,每次增加就重新申请,从而实现动态,其余思路和数组思路差不多一样。

    指针实现

    • 同样我们先想一下要什么全局变量

      int *p = NULL;
      int size = 0; //记录长度
      int choice;
      
    • 整体框架

      while (1)
      	{
      		printf("请输入你要的操作\n--1--添加元素\n--2--删除元素\n--3--输出元素和有多少元素\n--4--退出程序\n");
      		scanf("%d", &choice);
      		switch (choice)
      		{
      		case 1:
      			insert();//插入
      			break;
      		case 2:		 
      			delert();//删除,为啥不命名delete,因为是关键词
      			break;
      		case 3:
      			printAll();//输出
      			break;
      		case 4:
      			return 0;
      		break;
      		default:
      			break;
      		}
      		 
      	}
      
    • 添加元素

      void insert()
      {
      	printf("请输入要添加的元素:\n");
      	int input;
      	scanf("%d", &input);
      	//申请空间要用realloc,因为malloc是用于第一次申请新的空间,而要改动就要用realloc
      	p = (int)realloc(p, sizeof(int)*(size+1));//先申请扩大再放入,这里理解一下就是
      	                                          //你要先申请空的位置才能放东西
      	*(p + size) = input;
      	size++;
      }
      
    • 删除元素

      void delert()
      {
      	printf("请输入要删除的元素:\n");
      	int input;
      	scanf("%d", &input);
      	for (int i = 0; i < size; i++)
      	{
      		if (*(p+i) == input)
      		{
      			for (int j = i; j < size - 1; j++)
      			{
      				*(p+j) = *(p+j + 1);
      			}
      			p= (int)realloc(p, sizeof(int)*(size - 1));//先移动再缩小,你要清理了东西
      			                                           //才能减少空间
      			size--;
      			i--;
      		}
      	}
      }
      
    • 输出元素

      void printAll()
      {
      	printf("数组总共有%d个元素:\n", size);
      	for (int i = 0; i < size; i++)
      	{
      		printf("%d ",*(p + i));
      	}
      	printf("\n");
      }
      
    展开全文
  • 思路1:双指针i,j,i对数组进行遍历,如果i和i+1指向的元素值不同,则将j向右移动一格,并将i+1的值赋给 j,以此保证j的指向轨迹是一个新的不重复的数组。 int removeDuplicates(int* nums, int numsSize){ int...

    给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

    不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

    思路1:双指针i,j,用i对数组进行遍历,如果i和i+1指向的元素值不同,则将j向右移动一格,并将i+1的值赋给 j,以此保证j的指向轨迹是一个新的不重复的数组。

    int removeDuplicates(int* nums, int numsSize){
       int i,j;
       
       if(nums == NULL || numsSize==0)
       return 0;
       
       for(i=0,j=0;i<numsSize;i++)
       {
           if(nums[i]!=nums[i+1])
           {
               nums[++j]=nums[i+1];
           }   
       }
       return j+1;
    }

     执行出错:(目前不知道此思路哪里出了问题,贴出来看看有没有小伙伴能帮忙找出问题!)

    思路2:用新旧指针从头开始遍历数组,如果新旧指向的元素值不同,说明不是重复元素,新指针向右移动一格。

    int removeDuplicates(int* nums, int numsSize){
       if(nums==NULL || numsSize<=0)  return 0;//判断数组符不符合操作要求,非空,长度大于零
       int oldIndex=1,newIndex=0;//旧、新  指针
       for(;oldIndex<numsSize;oldIndex++)
       {
           if(nums[oldIndex]!=nums[newIndex])//旧、新指针指向数相同则循环,不相同则新指针前进且将非重复的值(即旧指针的值赋值给新指针)
           {
               nums[++newIndex]=nums[oldIndex];
           }
       }
       return newIndex+1;//返回非重复数组的长度
    }

    执行通过:

    【从今天开始就要坚持写题啦!每日更新,今日用时 1h,新手还是有些菜,希望能越来越好。】

    展开全文
  • 1) 动态数据结构概念 数组和结构体是定长数据结构而链表堆 栈队列树图等是执行时大小可变的动态数 据结构 链表是连成一行的数据项集合每一个数据 项(元素)称为节点可以在链表中的任意位置进 行节点插入或删除操作使...
  • 我们知道,用数组存放数据时,必须事先定义固定的长度(即元素个数). 比如,有的班级有100人,而有的班只有30人,如果要同一个数组先后存放不同班级的学生数据,则必须定义长度为100的数组.如果事先难以确定一个班的最多...

    链表是一种常见的重要的数据结构.它是动态地进行存储分配的一种结构。我们知道,用数组存放数据时,必须事先定义固定的长度(即元素个数).

    比如,有的班级有100人,而有的班只有30人,如果要用同一个数组先后存放不同班级的学生数据,则必须定义长度为100的数组.如果事先难以确定一个班的最多人数,则必须把数组定得足够大,以能存放任何班级的学生数据.显然这将会浪费内存.链表则没有这种缺点,它根据需要开辟内存单元。

    一、链表结构和静态/动态链表

    二、单链表的建立与遍历

    三、单链表的插入与删除

    四、双向链表的概念

    五、双向链表的建立与遍历

    六、双向链表的元素查找

    七、循环链表的概念

    八、合并两个链表的实例

    九、链表实战

    拓展思维、拉到最后去看看 (•̀ᴗ•́)و ̑̑

     

    一、链表结构和静态/动态链表

        链表是一种常见的数据结构——与数组不同的是:

            1.数组首先需要在定义时声明数组大小,如果像这个数组中加入的元素个数超过了数组的长度时,便不能正确保存所有内容;链表可以根据大小需要进行拓展。

            2.其次数组是同一数据类型的元素集合,在内存中是按一定顺序连续排列存放的;链表常用malloc等函数动态随机分配空间,用指针相连。

        链表结构示意图如下所示:

            

        在链表中,每一个元素包含两个部分;数据部分和指针部分。数据部分用来存放元素所包含的数据,指针部分用来指向下一个元素。最后一个元素的指针指向NULL,表示指向的地址为空。整体用结构体来定义,指针部分定义为指向本结构体类型的指针类型。

        静态链表需要数组来实现,即把线性表的元素存放在数组中。数组单元存放链表结点,结点的链域指向下一个元素的位置,即下一个元素所在数组单元的下标。这些元素可能在物理上是连续存放的,也有可能是不连续的,它们之间通过逻辑关系来连接——这就要涉及到数组长度定义的问题,实现无法预知定义多大的数组,动态链表随即出现。

        动态链表指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点的数据,并建立起前后相连的关系。

     

    二、单链表的建立与遍历

        单链表中,每个结点只有一个指针,所有结点都是单线联系,除了末为结点指针为空外,每个结点的指针都指向下一个结点,一环一环形成一条线性链。

        链表的创建过程:

            

     

        接下来在源码中建立并遍历输出一个单链表。

    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    
    /*单向链表*/
    struct Student/*建立学生信息结构体模型*/ 
    {
        char cName[20];/*学生姓名*/
        int iNumber;/*学生学号*/
        struct student *next;/*指向本结构体类型的指针类型*/
    };
    
    int iCount;/*全局变量表示链表长度*/ 
    
    struct Student *Create();/*创建链表函数声明*/ 
    void print(struct Student *);/*遍历输出链表函数声明*/
    
    int main()
    {
        int insert_n=2;/*定义并初始化要插入的结点号*/
        int delete_n=2;/*定义并初始化要删除的结点号*/
        struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/
        pHead=Create();/*创建链表,返回链表的头指针给pHead*/
        print(pHead);/*将指针pHead传入输出函数遍历输出*/
        return 0; 
    }
    
    struct Student *Create()
    {
        struct Student *pHead=NULL;/*初始化链表,头指针为空*/ 
        struct Student *pEnd,*pNew;
        iCount=0;/*初始化链表长度*/ 
        pEnd=pNew=(struct Student *)malloc(sizeof(struct Student));/*动态开辟一个学生信息结构体类型大小的空间,使得pEnd和pNew同时指向该结构体空间*/
        scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/ 
        scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/ 
        while(pNew->iNumber!=0)/*设定循环结束条件——学号不为0时*/ 
        {
            iCount++;/*链表长度+1,即学生信息个数+1*/ 
            if(iCount==1)/*如果链表长度刚刚加为1,执行*/ 
            {
                pNew->next=pHead;/*使指针指向为空*/
                pEnd=pNew;/*跟踪新加入的结点*/
                pHead=pNew;/*头结点指向首结点*/
            }
            else/*如果链表已经建立,长度大于等于2时,执行*/ 
            {
                pNew->next=NULL;/*新结点的指针为空*/
                pEnd->next=pNew;/*原来的结点指向新结点*/
                pEnd=pNew;/*pEnd指向新结点*/
            }
            pNew=(struct Student *)malloc(sizeof(struct Student));/*再次分配结点的内存空间*/
            scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/ 
            scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/ 
        }
        free(pNew);/*释放结点空间*/
        return pHead;/*返回创建出的头指针*/ 
    }
    
    void print(struct Student *pHead)
    {
        struct Student *pTemp;/*定义指向一个学生信息结构体类型的临时指针*/ 
        int iIndex=1;/*定义并出事哈变量iIndex,用来标识第几个学生(信息)*/ 
        printf("总共%d个学生(信息):\n",iCount);
        pTemp=pHead;/*指针得到首结点的地址*/ 
        while(pTemp!=NULL)/*当临时指针不指向NULL时*/ 
        {
            printf("第%d个学生信息:\n",iIndex); 
            printf("姓名:%s",pTemp->cName); /*输出姓名*/
            printf("学号:%d",pTemp->iNumber);/*输出学号*/
            pTemp=pTemp->next;/*移动临时指针到下一个结点*/ 
            iIndex++;/*进行自加运算*/ 
        }
    }

    三、单链表的插入与删除

        在本实例中,插入时根据传递来的学号,插入到其后。

        删除时根据其所在链表的位置,删除并释放该空间。

        主函数增加如下:

    int main()
    {
        int insert_n=2;/*定义并初始化要插入的结点号*/
        int delete_n=2;/*定义并初始化要删除的结点号*/
        struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/
        pHead=Create();/*创建链表,返回链表的头指针给pHead*/
        pHead=Insert(pHead,insert_n);/*将指针pHead和要插入的结点数传递给插入函数*/
        print(pHead);/*将指针pHead传入输出函数遍历输出*/
        Delete(pHead,delete_n);/*将指针pHead和要删除的结点数传递给删除函数*/
        print(pHead);/*将指针pHead传入输出函数遍历输出*/
        return 0; 
    }

    插入函数:

    struct Student *Insert(struct Student *pHead,int number)
    {
        struct Student *p=pHead,*pNew;/*定义pNew指向新分配的空间*/ 
        while(p&&p->iNumber!=number)
            p=p->next;/*使临时结点跟踪到要插入的位置(该实例必须存在学号为number的信息,插入其后,否则出错)*/ 
        printf("姓名和学号:\n");
        /*分配内存空间,返回该内存空间的地址*/ 
        pNew=(struct Student *)malloc(sizeof(struct Student));
        scanf("%s",pNew->cName);
        scanf("%d",&pNew->iNumber);
        pNew->next=p->next;/*新结点指针指向原来的结点*/
        p->next=pNew;/*头指针指向新结点*/
        iCount++;/*增加链表结点数量*/ 
        return pHead;/*返回头指针*/ 
    }

    删除函数:

    void Delete(struct Student *pHead,int number)
    {
        int i;
        struct Student *pTemp;/*临时指针*/ 
        struct Student *pPre;/*表示要删除结点前的结点*/ 
        pTemp=pHead;/*得到链表的头结点*/ 
        pPre=pTemp;
        for(i=0;i<number;i++)
        {/*通过for循环使得Temp指向要删除的结点*/ 
            pPre=pTemp;
            pTemp=pTemp->next; 
        }
        pPre->next=pTemp->next;/*连接删除结点两边的结点*/ 
        free(pTemp);/*释放要删除结点的内存空间*/ 
        iCount--;/*减少链表中的结点个数*/ 
    }

    四、双向链表的概念

        双向链表基于单链表。单链表是单向的,有一个头结点,一个尾结点,要访问任何结点,都必须知道头结点,不能逆着进行。而双链表添加了一个指针域,通过两个指针域,分别指向结点的前结点和后结点。这样的话,可以通过双链表的任何结点,访问到它的前结点和后结点。

        在双向链表中,结点除含有数据域外,还有两个链域,一个存储直接后继结点的地址,一般称为右链域;一个存储直接前驱结点地址,一般称之为左链域。

        双向链表结构示意图:

        

     

    五、双向链表的建立与遍历

         双向链表的源码实战和单链表类似,只是多了第二个指针域的控制,这里直接贴上没有注释的源代码。

    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #define N 10
    
    typedef struct Node
    {
        char name[20];
        struct Node *llink,*rlink;
    }STUD;
    
    STUD *creat(int);void print(STUD *);
    
    int main()
    {
        int number;
        char studname[20];
        STUD *head,*searchpoint;
        number=N;
        head=creat(number);
        print(head);
        printf("请输入你要查找的人的姓名:");
        scanf("%s",studname);
        searchpoint=search(head,studname);
        printf("你所要查找的人的姓名是:%s",*&searchpoint->name); 
        return 0;
    }
    
    STUD *creat(int n)
    {
        STUD *p,*h,*s;
        int i;
        if((h=(STUD *)malloc(sizeof(STUD)))==NULL)
        {
            printf("不能分配内存空间");
            exit(0);        
        }
        h->name[0]='\0';
        h->llink=NULL;
        h->rlink=NULL;
        p=h;
        for(i=0;i<n;i++)
        {
            if((s=(STUD *)malloc(sizeof(STUD)))==NULL)
            {
            printf("不能分配内存空间");
            exit(0);        
            }
            p->rlink=s;
            printf("请输入第%d个人的姓名",i+1);
            scanf("%s",s->name);
            s->llink=p;
            s->rlink=NULL;
            p=s;
        }
        h->llink=s;
        p->rlink=h;
        return(h);
    }
    
    void print(STUD *h)
    {
        int n;
        STUD *p;
        p=h->rlink;
        printf("数据信息为:\n");
        while(p!=h)
        {
            printf("%s ",&*(p->name));
            p=p->rlink;
        }
        printf("\n");
    }

    六、双向链表的元素查找

         查找函数  STUD *search(STUD *,char *);

    STUD *search(STUD *h,char *x)
    {
        STUD *p;
        char *y;
        p=h->rlink;
        while(p!=h)
        {
            y=p->name;
            if(strcmp(y,x)==0)
                return(p);
            else
                p=p->rlink;
        }
        printf("没有查到该数据!");
    }

    七、循环链表的概念

        类似于单链表,循环链表也是一种链式的存储结构,由单链表演化而来。

        单链表的最后一个结点的指针指向NULL,而循环链表的最后一个结点的指针指向链表头结点。

        这样头尾相连,形成了一个环形的数据链。

        循环链表的建立不需要专门的头结点。

        判断循环链表是否为尾结点时,只需判断该节点的指针域是否指向链表头节点。

     

    八、合并两个链表的实例

        建立两个带头节点的学生链表,每个节点包含学号、姓名和成绩,链表都按学号升序排列,将它们合并为一个链表仍按学号升序排列。

        算法分析:

            合并链表用merge()函数实现。函数中定义3个工作指针a、b、c,其中a、b分别指向La链表、Lb链表的当前结点,C指向合并后的链表尾结点。合并后链表的头结点共用La链表的头结点。

            ①合并前,先让a和b分别指向两个链表的第一个结点,c指向La链表的头结点。

            ②合并时应该分3种情况讨论,即La和Lb都没有处理完;La没处理完,但Lb处理完毕;Lb没处理完,但La处理完毕。

            ③合并过程中应始终将La和Lb链表中较小的一个链接在Lc中,方能保持有序。

    void merge(struct stud *La,struct stud *Lb)
    {
        struct stud *a,*b,*c;
        c=La;
        a=La->next;/* 合并前 */
        b=Lb->next;
        while(a!=NULL && b!=NULL)/* La和Lb都没处理完 */
        {
            if(a->num <= b->num)
            {
                c->next=a;
                c=a;
                a=a->next;
            }
            else
            {
                c->next=b;
                c=b;
                b=b->next;
            }
        }
        if(a!=NULL)
            c->next=a;/* 若La没有处理完 */
        else
            c->next=b;/* 若Lb没有处理完 */
        free(Lb); /* 释放Lb的头结点 */
    }

    九、实战

       源自《C语言程序设计-谭浩强》

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    // 没有
    // 每重新进一次main(),都产生一层函数嵌套,很多次后会发生什么 
    
    typedef struct Movie
    {
        int id;/*影片编号*/
        char name[20];/*影片名称*/
        char director[10];/*导演*/
        char actor[20];/*主演*/
        char date[10];/*上映日期*/
        float score;/*影片评分*/
        struct Movie *next;/*指向下一个节点的指针*/
    }Film;
    
    int iCount;
    Film *pMain=NULL;
    
    void menu();/*菜单*/ 
    Film *Create();/*创建链表函数声明*/
    void printAll(Film *head);/*显示所有影片的信息*/
    Film *findFilm(Film *,int);/*查询影片信息*/
    void printFilm(Film *Film);/*输出单个影片信息*/
    void modifyFilm(Film *,int);/*修改影片信息*/
    void deleteFilm(Film *,int);/*删除影片信息*/
    
    /* 统计链表长度,这里由iCount代替 */ 
    //int length(Film *);/*显示影片总数*/ 
    
    int main()
    {
        menu();
        return 0;
    }
    
    void menu()
    {
        int choice;
        int id;
        printf("\n\n");
        printf("\t------------------------------------\n");
        printf("\t|     欢迎使用影片信息管理系统     |\n");
        printf("\t------------------------------------\n");
        printf("\t|          1-录入影片信息          |\n");
        printf("\t|          2-查询影片信息          |\n");
        printf("\t|          3-修改影片信息          |\n");
        printf("\t|          4-删除影片信息          |\n");
        printf("\t|          5-显示所有影片          |\n");
        printf("\t|          6-  影片总数            |\n");
        printf("\t|          7-  退出程序            |\n");
        printf("\t请选择功能 1-7 :");
        scanf("%d",&choice);
        getchar();
        system("cls");
        switch(choice)
        {
            case 1:
                pMain=Create(); 
                if(pMain==NULL)
                    printf("\t录入出错了 =、=\n");
                else
                {
                    system("cls");
                    printf("\t成功录入%d个影片信息\n",iCount);
                } 
                menu();
                break;
            case 2:
                if(pMain==NULL)
                {
                    printf("\t没有任何影片可供查询\n");
                }
                else
                {
                    printf("\t输入查询的id:");
                    scanf("%d",&id);
                    printFilm(findFilm(pMain,id));
                }
                menu();
                break;
            case 3:
                if(pMain==NULL)
                {
                    printf("\t没有任何影片可供修改\n");
                }
                else
                {
                    printf("\t输入修改的id:");
                    scanf("%d",&id);
                    modifyFilm(pMain,id);
                    system("cls");
                    printf("\t修改成功\n");
                }
                menu();
                break;
            case 4:
                if(pMain==NULL)
                {
                    printf("\t没有任何影片可供删除\n");
                }
                else
                {
                    printf("\t输入删除的id:");
                    scanf("%d",&id);
                    deleteFilm(pMain,id); 
                    system("cls");
                    printf("\t删除成功\n");
                }
                menu();
                break;
            case 5:
                if(pMain==NULL)
                {
                    printf("\t没有任何影片可供显示\n");
                    menu();
                }
                else
                    printAll(pMain);
                menu();
                break;
            case 6:
                printf("\t影片总数为:%d",iCount);
                menu();
                break;
            case 7:
                exit(0);
                break;
            default:
                menu();
                break;
        }
    }
    
    Film *Create()
    {
        int flag;
        Film *pHead=NULL;
        Film *pNew,*pEnd;
        Film *qq;
        pEnd=pNew=(Film *)malloc(sizeof(Film));
        iCount=0;
        printf("\n\n\t该录入将重新赋值。\n");
        printf("\t请输入影片编号:");
        scanf("%d",&pNew->id);
        printf("\t请输入影片名称:");
        scanf("%s",pNew->name);
        printf("\t请输入导演:");
        scanf("%s",pNew->director);
        printf("\t请输入主演:");
        scanf("%s",pNew->actor);
        printf("\t请输入上映日期:");
        scanf("%s",pNew->date);
        printf("\t请输入影片评分:");
        scanf("%f",&pNew->score);
        printf("\n");
        printf("\t是否继续输入(1继续,其它则退出并返回主菜单):");
        scanf("%d",&flag);
        while(flag==1)
        {
            iCount++;
            if(iCount==1)
            {
                pNew->next=pHead;
                pEnd=pNew;
                pHead=pNew;
            }
            else
            {
                pNew->next=NULL;
                pEnd->next=pNew;
                pEnd=pNew;
            }
            pNew=(Film *)malloc(sizeof(Film));
            printf("\t请输入影片编号:");
            scanf("%d",&pNew->id);
            printf("\t请输入影片名称:");
            scanf("%s",pNew->name);
            printf("\t请输入导演:");
            scanf("%s",pNew->director);
            printf("\t请输入主演:");
            scanf("%s",pNew->actor);
            printf("\t请输入上映日期:");
            scanf("%s",pNew->date);
            printf("\t请输入影片评分:");
            scanf("%f",&pNew->score);
            printf("\n");
            printf("\t是否继续输入(1继续,其它则退出并返回主菜单):");
            scanf("%d",&flag);
        }
        iCount++;
        pNew->next=NULL;
        pEnd->next=pNew;
        pEnd=pNew;
        pNew=(Film *)malloc(sizeof(Film));
        free(pNew);
        return(pHead);
    }
    
    void printAll(Film *head)
    {
        Film *p=head;
        if(p)/*链表不为空时才输出表头*/ 
        {
            printf("    编号    名称    导演    主演    上映时间    评分    \n");
            printf("--------------------------------------------------------\n");
        }
        while(p)/*遍历链表,输出每个结点的信息*/
        {
            printf("\t%d\t%s\t%s\t%s\t%s\t\t%f\n",p->id,p->name,p->director,p->actor,p->date,p->score);
            p=p->next;
        }
    }
    
    Film *findFilm(Film *head,int id)
    {
        Film *p=head;
        while(p&&p->id!=id)/*如果p不为空并且p不是要找的结点*/ 
            p=p->next;/*令p指向下一个结点*/ 
        return p;
    }
    
    void printFilm(Film *film)
    {
        if(!film)/*如果指针为空,即不存在该结点*/ 
            printf("\t%s\n","没有查询到该影片的信息,请检查输入");
        else/*若指针不为空则输出影片信息*/ 
        {
            printf("    编号    名称    导演    主演    上映时间    评分    \n");
            printf("--------------------------------------------------------\n");
            printf("\t%d\t%s\t%s\t%s\t%s\t\t%f\n",film->id,film->name,film->director,film->actor,film->date,film->score);
        }
    }
    
    void modifyFilm(Film *head,int id)
    {
        Film *p=findFilm(head,id);/*首先查找该id的影片,将结果保存在p中*/ 
        if(p)/*如果查找到影片,则可以修改*/ 
        {
            printf("\t======================================================\n");
            printf("\t               ***** 修改影片信息 *****               \n");
            printf("\t======================================================\n");
            printf("该影片的信息如下:\n");
            printFilm(p);
            printf("\t请输入影片编号:");
            scanf("%d",&p->id);
            printf("\t请输入影片名称:");
            scanf("%s",p->name);
            printf("\t请输入导演:");
            scanf("%s",p->director);
            printf("\t请输入主演:");
            scanf("%s",p->actor);
            printf("\t请输入上映日期:");
            scanf("%s",p->date);
            printf("\t请输入影片评分:");
            scanf("%f",&p->score);
        }
        else
            printf("\t未查询到该影片的信息,请检查输入.\n");
    }
    
    void deleteFilm(Film *head,int id)
    {
        Film *q,*p=head;
        if(head->id==id)/*如果要删除的是头结点*/ 
        {
            head=(head->next);
            free(p);
        }
        else/*若要删除的不是头结点*/ 
        {
            while(p)/*遍历链表寻找要删除的结点*/ 
            {
                if(p->id==id)
                {
                    q->next=p->next;
                    free(p);/*释放内存空间*/ 
                    break;
                }
                q=p;/*q为p的前驱结点*/ 
                p=p->next;
            }
        }
    }
    
    /* 统计链表长度,这里由iCount代替 */ 
    //int length(Film *head)/*统计链表长度*/ 
    //{
    //    Film *p=head;
    //    int count=0;
    //    while(p)/*遍历链表*/ 
    //    {
    //        p=p->next;
    //        ++count;
    //    }
    //    return count;
    //}
    
    影片信息管理系统

     

    展开全文
  • 用数组实现线性表

    千次阅读 2012-08-04 14:07:02
    有12种基本的操作,分别是:初始化、删除、清空、判断是否为空、遍历、求表的长度、求某个元素在表中的位置、返回特定序号的元素、求某个元素的前一个元素、求某个元素的后一个元素、插入一个元素删除一个元素。...

    对于线性结构,有两种保存的方法,一种是使用C语言中内置的数组,这样的结构成为顺序表;另一种使用指针,这样的结构成为链表。

    对于线性结构,有12种基本的操作,分别是:初始化、删除、清空、判断是否为空、遍历、求表的长度、求某个元素在表中的位置、返回特定序号的元素、求某个元素的前一个元素、求某个元素的后一个元素、插入一个元素、删除一个元素。

    这一小节介绍如何利用数组实现线性表。

    先看程序:

     

    #include <stdio.h>
    #include <malloc.h>
    
    typedef int ElemType;
    
    
    typedef struct arraylist
    {
    
    	//实际存放元素的数组
    	ElemType *Array;
    	//数组中已经使用了多少元素
    	int length;
    	//数组的容量
    	int size;
    
    }arrayList;
    
    //初始化顺序表:给出初始化长度
    bool initialArray(arrayList *arrLst,int len)
    {
    	arrLst->length = 0;
    	arrLst->size = len;	
    	arrLst->Array = (ElemType*)malloc(len*sizeof(ElemType));
    	if(NULL == arrLst->Array)
    		return false;
    	else
    		return true;
    
    }
    
    //删除顺序表
    void deleteArray(arrayList *arrLst)
    {
    	arrLst->length = 0;
    	arrLst->size = 0;
    	free(arrLst->Array);
    	arrLst->Array = NULL;
    }
    
    //清空顺序表
    void clearArray(arrayList *arrLst)
    {
    	arrLst->length = 0;
    }
    
    //判断是否为空
    bool is_empty(arrayList *arrLst)
    {
    	
    	if(0 == arrLst->length)
    	{
    		printf("the arrayList is empty!\n");
    		return true;
    	}
    	else
    	{
    		printf("the arrayList is not empty!\n");
    		return false;		
    	}
    }
    
    //求有多少个元素
    int arrayLength(arrayList *arrLst)
    {
    	return arrLst->length;
    }
    
    //取出某个元素
    bool getElem(arrayList *arrLst,int index,ElemType *e)
    {
    	if(index < 0 || index > arrayLength(arrLst)-1)
    		return false;
    	else
    	{
    		*e = arrLst->Array[index];
    		return true;
    	}
    
    }
    
    //遍历顺序表,并打印
    void printArray(arrayList *arrLst)
    {
    	printf("array elements are: ");
    	for(int i = 0; i < arrayLength(arrLst);++i)
    	{
    		printf("%d\t",arrLst->Array[i]);
    	}
    	printf("\n");
    }
    
    //判断某个元素的位置
    int locateElem(arrayList *arrLst,ElemType e)
    {
    	for(int i = 0; i < arrayLength(arrLst);++i)
    	{
    		if(e == arrLst->Array[i])
    			return i;
    	}
    	return -1;
    
    }
    
    //求某个元素的前驱:如果没找到返回-2;如果是第一个元素。返回-1;否则返回前驱元素的下标
    int preElement(arrayList *arrLst,ElemType e,ElemType *preElem)
    {
    	for(int i = 0 ; i < arrayLength(arrLst); ++i)
    	{
    		//如果找到了
    		if(e == arrLst->Array[i])
    		{
    			//如果是第一个元素
    			if(0 == i)
    			{
    				return -1;
    			}
    			else
    			{
    				*preElem = arrLst->Array[i-1];
    				return i-1;
    			}
    		}
    	}
    	return -2;
    }
    
    
    //求某个元素的后继:如果没找到,返回-2,如果是最后一个元素,返回-1;否则返回后继元素的下标
    int nextElement(arrayList *arrLst,ElemType e,ElemType *nxtElem)
    {
    	for(int i = 0; i < arrayLength(arrLst); ++i)
    	{
    		if(e == arrLst->Array[i])
    		{
    			if(arrayLength(arrLst) -1 == i)
    			{
    				return -1;
    			}
    			else
    			{
    				*nxtElem = arrLst->Array[i+1];
    				return i+1;
    			}
    		}
    	}
    	return -2;
    }
    
    //将元素插入到指定位置
    bool insertElem(arrayList *arrLst,int index ,ElemType e )
    {
    	//先判断插入位置是否合法
    	if(0 > index ||  arrayLength(arrLst) < index)
    		return false;
    
    	//如果顺序表存储空间已满,则需要重新分配内存
    	if(arrLst->length == arrLst->size)
    	{
    		arrLst->Array = (ElemType*)realloc(arrLst->Array,2*arrLst->size*sizeof(ElemType));
    		if(NULL == arrLst->Array)
    			//分配失败,程序退出
    			return false;
    		else
    			//分配成功,扩容
    			arrLst->size *= 2;
    	}
    	//将插入点之后的元素后移
    	for(int i = arrayLength(arrLst); i > index; --i)
    		arrLst->Array[i] = arrLst->Array[i-1];
    	//插入元素
    	arrLst->Array[index] = e;
    	//顺序表长度自增
    	++arrLst->length;
    	return true;
    }
    
    
    bool deleteElem(arrayList *arrLst,int index ,ElemType *e)
    {
    	if(index < 0 || index > arrayLength(arrLst)-1)
    		return false;
    	*e = arrLst->Array[index];
    	//将删除点的元素依次左移
    	for(int i = index; i < arrayLength(arrLst);++i)
    	{
    		arrLst->Array[i] = arrLst->Array[i+1];
    	}
    	--arrLst->length;;
    	return true;
    }
    


     

    大部分程序都很简单,唯一需要说明的是,再插入元素时,如果线性表已满,需要重新分配内存空间,新分配的内存空间设定为原来的2倍。这个倍数也不是我随便给出的,我是参考C++中STL里面的vector给出的。相信那些专家,肯定考虑了倍数过小而导致多次分配内存与内存分配太大的折中,我也就照猫画虎的这样做了。

    其他的复杂的操作,大多数都能通过这些基本操作来完成,这里就不在列出了。

    我们可以看出,利用数组来表示线性结构,最大的优点在于由于数组是连续储存的,所以随机访问速度非常快,只需要用数组的首地址+下标*sizeof(结构体)就能计算指定元素的地址了。而它的缺点也很明显:就是插入、删除时效率很低,因为要移动大量的元素,甚至需要重新分配内存。

    最后说一句,程序是没有标准答案的,我自己写的程序也难免有各种错误,如果指出错误,我将不胜感激。

     

    展开全文
  • 在学习C语言的时候,我们已经学习过了数组,那时对数组的操作主要是生成数组、对数组的元素赋值、读取数组中的元素等内容,并没有对数组中的元素进行删除、插入操作。在本章内容中,我们将对数组的其它方面进行讲解...
  • 用数组描述的线性链表又叫静态链表。 静态链表中,元素存放...这种存储结构像顺序表一样需要预分配一段较大的空间,但在插入删除元素时不需要移动元素,只需要修改游标,所以具有链表的优点。 静态链表内部分为数据...
  • 定义:和栈相反,队列是一种先进先出的线性表,它只允许在表的一端进行插入,在另一端进行删除元素。在队列中,允许插入的一端叫队尾,允许删除的一端较队头,即入队只能从队尾入,出队只能从队头出。 2.初始化建...
  • 关于这个题,个人主要遇到的问题是...首先题目是要去不能别的数组的。 因为是原地删除,这样的话,只需要判断这个值是不是你要删除的那个,是的话就把它覆盖掉就完事了。 见代码。 /** * -*- coding: utf-8 -*-...
  • 动态顺序表相较于静态顺序表的优点:开辟的空间灵活自如,添加元素时自动增容,删除元素时自动减容,节省内存空间。 *注意:malloc开辟的内存空间以后调用销毁空函数destory_mylist(&my_list)进行内存释放。 ...
  • 这道题很明显需要用到栈这个数据结构,我们可以用数组来模拟实现栈,top为栈顶指针,当top = -1时表示栈为空,当栈中有一个元素时, top = 0。从头依次取出S中的字符放入栈中,若栈顶元素与S的当前首元素相同,则...
  • 本博文为半摘记性质,全文主干部分改编自《数据结构(C语言版)》,北京理工大学出版社,杨智明主编 —— 链表是一种物理存储单元上非连续、非顺序的数据结构,数据元素的逻辑顺序...结点之间的联系可以用指针实现,...
  • c语言经典案例

    2014-10-30 08:06:57
    实例175 用指针数组构造字符串数组 248 实例176 用指针函数输出学生成绩 249 实例177 寻找相同元素的指针 251 实例178 查找成绩不及格的学生 252 实例179 使用指针实现冒泡排序 254 实例180 输入月份号并输出英文...
  • C语言数据结构

    2020-08-21 00:07:06
    这种存储结构,仍需要预先分配一个较大的空间,但在作为线性表的插入和删除操作时,不需要移动数据元素,只需要修改指针(在这里是修改游标和数组下标),具有链式结构的主要优点 假如有如上的静态链表S中存储着
  • c语言链表创建

    2018-10-23 11:31:28
    详细用c语言创建链表,通俗易懂链表是一种常见的基础数据结构,结构体指针在这里得到了充分的利用。链表可以动态的进行存储分配,也就是说,链表是一个功能极为强大的数组,他可以在节点中定义多种数据类型,还可以...
  • C语言实现静态链表介绍 静态链表其实是为了给没有指针的编程语言设计的一种实现单链表功能的方法。 3.1静态链表的优缺点 ...2、一个数组分量表示一个节点,cur代替指针指示节点在数组中的相对位置
  • 用C语言实现线性表的顺序存储实现其实就是封装一个动态数组结构,其中包括: 指向堆区的数组指针 数组的容量(一般通过宏定义) 数组最后一个元素数组下标 类似的,C++中的STL封装的vector也是动态数组,但是得益...
  • C语言——链表笔记

    2018-03-10 16:35:36
    我们至少可以两种方式存储数据 1、数组 ...链表每个单元分两部分,左边存储实际元素值,右边存储下一个元素指针 链表术语: 头结点:头结点的数据类型和首节点的类型一样;头结点是首节点前...
  • 你必须知道的495个C语言问题

    千次下载 热门讨论 2015-05-08 11:09:25
    4.4 我用指针操作int数组的时候遇到了麻烦。 4.5 我有一个char*型指针碰巧指向一些int型变量,我想跳过它们。为什么((int*)p)++;这样的代码不行? 4.6 为什么不能对void*指针进行算术操作? 4.7 我有些解析...
  • C语言实现环形链表

    千次阅读 2015-08-31 20:52:07
    虽然现在开发多用Java了,闲着没事拿指针来练练手还是挺有意思的。约瑟夫的问题的解决方案有很多,可以一个循环10不到解决,...一维数组加两个循环也可以,这种删除一个数据,后面元素的下标都要跟着变,不太可取。
  • 数组的搜索比较方便,可以直接下标,但删除或者插入某些元素就比较麻烦。 链表与之相反,删除和插入元素很快,但查找很慢。 二叉排序树就既有链表的好处,也有数组的好处。 在处理大批量的动态的数据是比较有用。 ...
  • C语言常用算法

    2012-03-28 10:48:37
    012 一维数组统计学生成绩 013 二维数组实现矩阵转置 014 求解二维数组的最大/最小元素 015 利用数组求前n个质数 016 编制万年历 017 对数组元素排序 018 任意进制数的转换 019 判断回文数 020 求数组前...
  • 一般用于在没有指针等灵活操作内存的高级语言中,如早期的Basic、Fortran等编程语言,静态链表这种存储结构,仍需要预先分配一个较大的空间,但在作为线性表的插入和删除操作时不需移动元素,仅需修改指针,故仍具有...
  • C语言学习实例220例

    2015-06-16 23:47:59
    c语言开发实例目录: 第一部分 基础篇 001 第一个C程序 002 运行多个源文件 003 求整数之积 004 比较实数大小 005 字符的输出 006 显示变量所占字节数 007 自增/自减运算 008 数列求和 009 乘法口诀表 010 猜数字...
  • C语言实例解析精粹

    2014-03-14 21:57:05
    012 一维数组统计学生成绩 013 二维数组实现矩阵转置 014 求解二维数组的最大/最小元素 015 利用数组求前n个质数 016 编制万年历 017 对数组元素排序 018 任意进制数的转换 019 判断回文数 020 求数组前...
  • /*输入两个整型数组,假设数组大小为7,输出不是两个数组...[图片说明](https://img-ask.csdn.net/upload/201602/15/1455541718_676248.png)本来打算用指针进行移动变相的删除字符串,但是发生错误,基础不太扎实,求解
  • 一. 算法 通俗的定义: 解题的方法和步骤 狭义的定义: 对存储数据的操作 广义的定义: 广义的算法也叫泛型 无论数据是如何存储的,对该数据的操作... 链表一个节点中应包含一个指针变量,它来存放下一个节点的地址

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 153
精华内容 61
关键字:

c语言用指针删除数组元素

c语言 订阅