Bootstrap

线性表-c语言

定义

线性表:零个或多个数据元素的有限序列。
首先,他是一个序列,元素之间是有顺序的,若存在多个元素,**则第一个无前驱,最后一个无后继,其他元素每个元素都有且只有一个前驱和后继。 **然后,线性表强调是有限的,元素的个数是有限的。

线性表元素的个数n(n>-0)定义为线性表的长度,当n=0时,称为空表。
在复杂的线性表中,一个数据元素可以由若干个数据项组成。相同类型的数据。

线性表的抽象数据类型

ADT 线性表(List)
Data
线性表的数据对象集合为{a1,a2,......,an},每个元素的类型均为DataType。其中,除第一个元素a1外,每一个元素有且只有一个直接前驱元素,除了最后一个元素an外,每一个元素有且只有一个直接后驱元素,数据元素直接的关系是一一对应的关系。
Operation
InitList(*L): 初始化操作,建立一个空的线性表L。
ListEmpty(L): 若线性表为空,,返回true,否则返回false。
ClearList(*L): 将线性表清空。
GetElem(L,i,*e): 将线性表L中的第i个位置元素值返回给e。

//此为大话数据结构中的简单例子,可以忽略
void unionL(List *La,List Lb)
{
    int La_len,Lb_len,i;
    ElemType e;		//声明与La和Lb相同的数据元素e
    La_len = ListLenght(*La);	//求线性表的长度
    for (i=1; i<=Lb_len; i++)
    {
        GetElem(Lb, i, &e);		//取Lb中第i个数据元素附给e
        if(!LocateElem(*La, e))	//La中不存在和e相同数据元素
            ListInsert(La, ++La_len, e);	//插入
	}
}
顺序存储结构
//结构代码
typedef struct LinkList{
    int data[MAXSIZE];
    int length;
}list;
//获取元素
int get_elem(list l, int i,int *e){
    if (l.length==0 || i<1 || i>l.length)
        return 0;
    *e=l.data[i-1];
    return 1;
}
//插入元素
int list_insert(list* l, int i, int e){
    int k;
    if (l->length==MAXSIZE)
        return 0;
    if (i<1 || i>l->length+1)
        return 0;
    if (i<=l->length){
        for (k=l->length;k>=i-1;k--){
            l->data[k+1]=l->data[k];
        }
    }
    l->data[i-1]=e;
    l->length++;
    for (int i = 0; i < l->length; ++i) {
        printf("%d",l->data[i]);
    }
    return 1;
}
//删除元素
int list_delete(list *l, int i, int *e){
    int k;
    if (l->length==0)
        return 0;
    if (i<1 || i>l->length)
        return 0;
    *e=l->data[i-1];
    if (i<l->length){
        for (k = i; k < l->length; ++k) {
            l->data[k-1]=l->data[k];
        }
    }
    l->length--;
    for (int i = 0; i < l->length; ++i) {
        printf("%d",l->data[i]);
    }
    return 1;
}
//查找线性表中与e相等的元素
int locate_elem(list l, int e){
    if (l.length==0)
        return 0;
    for (int i=0; i<l.length; ++i){
        if (l.data[i]==e)
            return i+1;
    }
    return 0;
}
链式存储结构

链表中的第一个结点的存储位置叫做头指针,有时为了方便操作,会在单链表的第一个结点前附设一个结点。称为头结点。
头结点的数据域可以不存储任何信息。

结点由存放数据元素的数据域和存放后继结点地址的指针域组成。

//线性表的单链表存储结构
typedef struct node{
    int data;
    struct node* next;
}node;
typedef struct node *linklist;	//定义struct node* 的linklist,之后进行修改链表的操作时,直接使用linklist代表struct node*。
//创建链表
linklist * initlink(){
    linklist p=(linklist*)malloc(sizeof(linklist));    //头节点p
    linklist temp=p;   //头指针
    for (int i = 0; i < 5; ++i) {
        linklist a=(linklist*)malloc(sizeof(linklist));
        a->data=i;
        a->next=NULL;
        temp->next=a;
        temp=temp->next;
    }
    return p;
}
//获取第i个元素
int get_elem(linklist l, int i, int* e){  
    int j;
    linklist p;
    p = l->next;
    j = 1;
    while (p && j<i){
        p = p->next;
        ++j;
    }
    if (!p || j>i)
        return 0;
    *e = p->data;
    return 1;
}
//插入
int list_insert(linklist l, int i, int e){
    int j;
    linklist p,s;
    p = l;
    j = 1;
    while (p && j<i){
        p = p->next;
        ++j;
    }
    if (!p || j>i)
        return 0;
    s=(linklist)malloc(sizeof(node));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return 1;
}
//删除
int list_delete(linklist l, int i, int* e){//如上所说,此处的l可以理解为一个指向实参的指针,所以修改了l的数据,也就是修改了实参的数据
    int j=1;
    linklist p,q;
    p = l;
    while (p->next && j<i){     //寻找第i-1个节点
        p=p->next;
        ++j;
    }
    if (!p->next)       //若链表末尾为空,第i个节点不存在
        return 0;
    q=p->next;          //p->next为将删除的结点
    p->next=q->next;    //将q的后继赋值给p的后继
    *e=q->data;         //将q结点中的数据给e
    free(q);            //回收该节点,释放内存
    return 1;
}

单链表的整表创建

//单链表的整表创建
//头插法
void create_list_head(linklist l, int n){
    linklist p;
    int i;
    srand(time(0));
    l = (linklist)malloc(sizeof(node));
    l->next=NULL;
    for (int i = 0; i < n; ++i) {
        p=(linklist)malloc(sizeof(node));
        p->data=rand()%100+1;
        p->next=l->next;
        l->next=p;
    }
}
//尾插法
void create_list_tail(linklist l, int n){
    linklist p,r;
    int i;
    srand(time(0));
    l=(linklist)malloc(sizeof(node));
    r=l;
    for (int i = 0; i < n; ++i) {
        p=(node*)malloc(sizeof(node));
        p->data = rand()%100+1;
        r->next=p;
        r=p;
    }
    r->next=NULL;
}
//删除链表,将链表置空
int clear_list(linklist l){
    linklist p,q;
    p=l->next;
    while (p){
        q=p->next;
        free(p);
        p=q;
    }
    l->next=NULL;
    return 1;
}
单链表结构与顺序存储结构优缺点

存储分配方式

  • 顺序存储结构用一段连续的存储单元依次存储线性表的数据元素
  • 单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素

时间性能

  • 查找:顺序存储结构O(1)、单链表O(n)
  • 插入和删除:顺序存储结构需要平均移动表长一半的元素,时间为O(n)、单链表找出某位置的指针后,仅为O(1)

空间性能

  • 顺序存储结构需要预分配存储空间,分大了浪费,小了容易溢出
  • 单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制
//这里简单写个main函数调用以上顺序存储结构的函数,链式相同不再重复
#include <stdio.h>
#define MAXSIZE 20

typedef struct LinkList{
    int data[MAXSIZE];
    int length;
}list;

int get_elem(list l, int i,int *e){
    if (l.length==0 || i<1 || i>l.length)
        return 0;
    *e=l.data[i-1];
    return 1;
}
int list_insert(list* l, int i, int e){
    int k;
    if (l->length==MAXSIZE)
        return 0;
    if (i<1 || i>l->length+1)
        return 0;
    if (i<=l->length){
        for (k=l->length;k>=i-1;k--){
            l->data[k+1]=l->data[k];
        }
    }
    l->data[i-1]=e;
    l->length++;
    for (int i = 0; i < l->length; ++i) {
        printf("%d",l->data[i]);
    }
    return 1;
}
int list_delete(list *l, int i, int *e){
    int k;
    if (l->length==0)
        return 0;
    if (i<1 || i>l->length)
        return 0;
    *e=l->data[i-1];
    if (i<l->length){
        for (k = i; k < l->length; ++k) {
            l->data[k-1]=l->data[k];
        }
    }
    l->length--;
    for (int i = 0; i < l->length; ++i) {
        printf("%d",l->data[i]);
    }
    return 1;
}
int locate_elem(list l, int e){
    if (l.length==0)
        return 0;
    for (int i=0; i<l.length; ++i){
        if (l.data[i]==e)
            return i+1;
    }
    return 0;
}
int main() {
    //printf("Hello, World!\n");
    list l1;
    int num,num1;
    for (int i=0; i<10; i++){
        l1.data[i]=i;
        l1.length++;
    }
    get_elem(l1, 9, &num);
    printf("%d\n",num);
    list_insert(&l1,5,100);
    printf("\n");
    list_delete(&l1, 1, &num1);
    printf("\n");
    printf("%d",locate_elem(l1,1));

    return 0;
}
;