zoukankan      html  css  js  c++  java
  • c语言进阶12-线性表之顺序表

    一、  线性表的定义

    为什么要学习线性表呢?

    因为我们日常生活中存在种数据关系,计算机程序是为了解决日常生活的数据关系,因此我们要学习线性表。

    线性表是什么呢?

    线性表是由n个元素组成的有限序列。

    需要强调几点:

    1. 1.        首先它是一个序列。也就是说元素之间是有顺序的,若元素有多个,则第一个元素无前驱,最后一个元素无后继,其他每个元素都有且只有一个前驱和后继。
    2. 2.        其次强调一个有限的元素个数。

    例子1:

    例子2:

    大家判断是不是线性表?

    答: 当然是,符合线性表的定义。

    例子3:

        大家再思考一下公司的组织架构,是不是线性表表呢?

        答: 当然不是了,因为每一个元素,都不只一个后继,所以它不是线性表。

    例子4:

        大家思考,班级同学的友谊关系是不是线性表?

    答:当然不是了,因为每个同学可以建立多个友谊关系,不满足线性表的定义,

    例子:5

        大家思考,班级同学的点名,是不是线性表示?

    答:    是,因为点名是按顺序进行的,满足类型相同的特点。其中每个元素除了学生的学号外,还可以有学生的姓名、性别、出生年月日等。这些具体信息构成了一条数据项。

    在复杂的线性表中,一个数据元素可以由若干个数据项组成。

    二、  线性表的顺序存储结构

    1. 1.        顺序存储定义

    我们来看看线性表的两种物理结构的第一种——顺序存储结构。线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。

    例子1 :

              这就是很形象的顺序存储结构。

    1. 2.        顺序存储方式

    线性表的顺序存储结构,说白了,和刚才的例子一样,就是在内存中找了块地儿,通过占位置的形式,把一定的内存空间给占了,然后把相同数据类型的数据元素依次存放在这块空地中。既然线性表的每个元素的类型都相同,所以可以C语言的一维数组实现顺序存储结构,即把第一个数据元素存到数据下标为0的位置中,接着把线性表相邻的元素存储在数组中相邻的位置。这个接着,因为我们一共9个人,所以他需要占9个座。线性表中,我们估算这个线性表最大存储容量,建立一个数组,数组的长度就是这个最大存储点容量。

    ·来看线性表的顺序存储的结构代码

    #define MAXSIZE 20    /*存储空间初始分配量*/

    typedef int ElemType;    /* ElemType  类型根据实际情况而定,这里假设为int*/

    typedef struct

    {

        ElemType data[MAXSIZE];     /*数组存储数据元素,最大值为MAXSIZE */

    int length;                   /*线性表当前长度*/

    }Sqlist;

    这里,我们就发现描述顺序存储结构需要三个属性:

    1、存储空间的起始位置:数组data,它的存储位置就是存在空间的存储位置。

    2、线性表的最大存储容量:数组长度MaxSize.

    3、线性表的当前长度:length.    Length<=MaxSize

    1. 3.        数据长度与线性表长度区别

    这里有两个概念”数组长度”和“线性表的长度”需要区分一下。数组的长度是存放线性表的存储空间的长度。线性表的长度是线性表中元素个数,随着线性表插入和删除操作的进行,这个量是变化的。在任何时刻,线性表的长度应该小于等于数组的长度。

    1. 4.        地址计算方法

    由于我们数数都是从1开始数的,线性表的定义也不能避免,起始也是1,可C语言中的数组却是从0开始的第一个下标,于是线性表的第i个元素是要存储在数组下标为i-1的位置,即数组元素的序号和存放它的数组下标之间存在对应关系。

    用数组存储顺序表意味着要分配固定长度的数组空间,由于线性表中可以进行插入和删除操作,因此分配的数组空间要大于等于当前线性表的长度。

    其实,内存中的地址,就和图书馆或电影院里的座位一样,都是编号的。存储器中的每个存储单元都有自己的编号,这个编号称为地址。假设占用的是c个存储单元,那么线性表第i+1个数据元素的存储位置和第i个数据元素的存储位置满足下列关系:

    通过这个例子,你可以随时计算出线性表中任意位置的地址,不管它是第一个还是最后一个,都是相同的访问时间。那么我们就可以对每个线性表位置的存入或者取出数据,对于计算机来说都是相等的时间,也就是一个常数,因此用我们算法中学到的时间复杂度的概念来说,它的存储时间性能为O(1)。我们通常把具有这一个特点的存储结构称之为随机存取结构。

    三、  顺序存储结构的插入与删除

    1. 1.        ACM算法:顺序表的插入操作

    刚才我们也谈到,这里的时间复杂度为O(1)。我们考虑,如果我们要实现ListInsert,即在线性表L中的第i个位置插入新元素e,应该如何操作?

    举个例子,本来我们在春运时候去买火车票,大家都排队的好好的。这时来了一个美女,对着队伍中排在第三位的你说,“大哥,求求你帮帮忙,我家母亲病了,我得着急回去看她,这队伍这么长,你可否让我排在你的前面?”你心一软,就同意了。这时,你必须的退一步。这个例子其实已经说明了线性表的顺序结构,在插入数据时的现实的实现过程。

    插入算法的思路:

    (1)     如果插入位置不合理,抛出异常;

    (2)     如果线性表长度大于等于数组长度,则抛出异常或动态增加容量;

    (3)     从最后一个元素开始向前遍历到第i个位置,分别将它们都向后移动一个位置;

    (4)     将要插入元素填入位置i处;

    (5)     表长加1;

    实现代码如下:

    #define OK 1

    # define ERROR 0

    # define TRUE 1

    # define FALSE 0

    typedef int Status;

    1. 2.        ACM算法:顺序表的删除操作

    删除算法的思路:

    (1)     如果删除位置不合理,抛出异常;

    (2)     取出删除元素;

    (3)     从删除元素位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置;

    (4)     表长减1;

    链表实现代码

    /* Note:Your choice is C IDE */
    #include "stdio.h"
    #include "string.h"
    #include "stdlib.h"
    typedef struct person{
        int id;
        char name[20];
        struct person *next;
    }PERSON;
    PERSON *head;
    void lines(PERSON *p){
        PERSON *pa,*pb;
        pb=head;
        if(head==NULL){
            head=p; //链表头指针指向插入节点
        }
        else {
        while(pb){
            pa=pb;//第一次将头指针的指向赋给pa其他直接将自己指向的传给pa
            pb=pb->next;//pb变为指向下一个节点的指针
        }//循环完后p变为
        pa->next=p;
        }
        p->next=NULL;
    } 
    void charu(int j)
    {
        int p=0,i;
        PERSON *pa,*pb,*pc;
        pb=head;
        while(pb!=NULL)
        {
            pb=pb->next;
            p++;
            }
        pa=head;
        printf("
    现在的节点共%d个
    ",p);
        if(j<0||j>p){
            printf("输入数字有误!");
        }else {
            for(i=0;i<j;i++)
            {
                pb=pa;
                pa=pa->next;
            }
            printf("输入插入内容
    ");
            pc=(PERSON*)malloc(sizeof(PERSON));
           if(!pc){
            printf("内存分配失败!");
            exit(0);
            }
            printf("请输入id:");
            scanf("%d",&pc->id);
            printf("请输入名字:");
            fflush(stdin);
            gets(pc->name);
            pb->next=pc;
            pc->next=pa;
        }
    }
    void Delete(int j)
    {
        int p=0,i;
        PERSON *pa,*pb;
        pb=head;
        while(pb!=NULL)
        {
            pb=pb->next;
            p++;
            }
        pa=head;
        printf("
    现在的节点共%d个
    ",p-1);
        if(j<=0||j>p){
            printf("输入数字有误!");
        }else if(j==1){
            pb=pa->next;
            head=pb;
            free(pa);
        }else 
         {
             for(i=1;i<j;i++)//找到要找一个
             {
                 pb=pa;
                 pa=pa->next;
             }
             pb->next=pa->next;         
             free(pa);
          }
        }
    void main()
    {
       int i=0;
       int j;
       PERSON *p;
       PERSON *pp;
        char ch;
        do{
            //动态生成一个对象
             p=(PERSON*)malloc(sizeof(PERSON));
           if(!p){
            printf("内存分配失败!");
            ch=getchar();
            exit(0);
            }
            printf("请输入id:");
            scanf("%d",&p->id);
            printf("请输入名字:");
            fflush(stdin);
            gets(p->name);
        
            lines(p);
            printf("是否继续:");
            ch=getchar();
            fflush(stdin);
            i++;
        }while(ch=='y'||ch=='Y');
        printf("准备插入在第几个:");
        scanf("%d",&j);
        charu(j);
        pp=head;
         while(pp!=NULL){
             printf("%d  %s
    ",pp->id,pp->name);
             pp=pp->next;
         }
         printf("你想删除第几个:");
         scanf("%d",&j);
         Delete(j);
         pp=head;
         while(pp!=NULL){
             printf("%d  %s
    ",pp->id,pp->name);
             pp=pp->next;
         }
    }

    单链表无空头

    #include "stdio.h"
    #include "stdlib.h"
    int i;//循环变量
    struct nobe
    {
        int data;
        struct nobe *next;
    }*head;
    void lines(struct nobe *p);//输入结点
    void output();//输出节点
    void delet();//删除一个节点
    void cls();
    void input();
    void main()
    {
        struct nobe *p;
        int bh;
        for(;;){
        printf("请选择链表功能:
    ");
        printf("1.创建链表
    ");
        printf("2.输出链表
    ");
        printf("3.删除节点
    ");
        printf("4.清空链表
    ");
        printf("5.插入节点
    ");
        printf("0.退出
    ");
        printf("请输入功能编号:");
        scanf("%d",&bh);
        switch(bh)
        {
            case 1:
            printf("您选择的是常见链表功能:
    ");
            for(i=0;i<5;i++)
            {
                p=(struct nobe*)malloc(sizeof(struct nobe ));
                if(!p)
                {
                    printf("分配失败!");
                    }
                printf("请输入第%d个节点的数据域的数据:
    ",i+1);
                scanf("%d",&p->data);
                fflush(stdin);
                lines(p);
                }
            break;
            case 2:
            output();
            break;
            case 3:
            delet();
            break;
            case 4:
            cls();
            break;
            case 5:
            input();
            break;
            case 0:
            exit(0);
            break;
            default :
            printf("您输入的功能编号有误!
    ");
            break;
                }
        }
    }
    void lines(struct nobe *p)//输入结点
    {
        struct nobe *pa,*pb;
        pa=head;
        if(head==NULL)
        {
            head=p;//将第一个节点当作表头
        }else
        {
            while(pa)
            {
                pb=pa;
                pa=pa->next;
            }    
            pb->next=p;        
        }
        p->next=NULL;
    }
    void output()//输出节点
    {
        struct nobe *p;
        p=head;
        if(head==NULL)
        {
            printf("暂无数据
    ");
        }else
        {
            while(p)
            {
                
                printf("%d    ",p->data);
                p=p->next;
            }
            printf("
    ");
            }
    }
    void delet()
    {
        struct nobe *pa,*pb;
        int a;
        if(head==NULL)
        {
            printf("暂无数据
    ");
        }else
        {
            printf("请输入您准备删除的数据:");
            scanf("%d",&a);
            pa=head;
            while(pa)
            {            
                if(pa->data==a)
                {
                    break;
                    }
                pb=pa;//pa等于他前一个节点
                pa=pa->next;
            }
            if(pa==NULL)
            {
                printf("您输入的数据有误!
    ");
                }
            else if(pa->next==NULL)
            {
                pb->next=NULL;
                free(pa);
            }else{
            pb->next=pa->next;
            free(pa);
            printf("删除成功!
    ");
            }        
            }
        
    }
    void cls()
    {
        struct nobe *pa,*pb;
        if(head==NULL)
        {
            printf("暂无数据
    ");
        }else
        {
            pa=head;
            while(pa)
            {                        
                pb=pa;//pa等于他前一个节点
                pa=pa->next;
                free(pb);
            }
            head=NULL;
            }
    }
    void input()
    {
        int n;
        struct nobe *p,*pa;
        p=(struct nobe *)malloc(sizeof(struct nobe));
        pa=head;
        printf("请输入要插入在第几个之后:");
        scanf("%d",&n);
        printf("输入数据:");
        scanf("%d",&p->data);
        if(n==0)
        {
            head=p;
            p->next=pa;
            }else{
                for(i=1;i<n;i++)
                {
                    pa=pa->next;
                }
                p->next=pa->next;
                pa->next=p;}
                printf("插入成功
    ");    
        }

    队列的实现代码

    /* Note:Your choice is C IDE */
    #include "stdio.h"
    struct person{
        int age[20];
        int top;
        int rear;
    };
    void fun1(struct person *s){
        int n;
        printf("输入数字:");
        scanf("%d",&n);
        
        if(s->rear<=20){
            s->age[s->rear]=n;
            s->rear++;
        }
        
    }
    void fun2(struct person *s){
        if(s->top!=s->rear){
            s->top++;
        }else
        {
            printf("无内容
    ");
            }
    }
    void fun3(struct person *s)
    {
        int i;
        for(i=s->top;i<s->rear;i++)
        {
            printf(" %d 
    ",s->age[i]);
            }
        }
    void main()
    {
        struct person s;
        int bh;
        s.top=0;
        s.rear=0;
        for(;;){
        printf("1.入列
    2.出列
    3.输出
    ");
        scanf("%d",&bh);
        switch(bh)
        {
            case 1:
            fun1(&s);
            break;
            case 2:
            fun2(&s);
            break;
            case 3:
            fun3(&s);
            break;
                }
        }
    }
  • 相关阅读:
    css3新特性
    线程间通信的三种方法
    硬件相关知识
    time.h
    ldr指令总结
    你不知道的100个小秘密
    ARM学习日记
    C中位域的使用
    《编程之美》第2刷勘误
    排序2
  • 原文地址:https://www.cnblogs.com/TimVerion/p/11193408.html
Copyright © 2011-2022 走看看