数据结构知识点【第二章线性表】

 

2.1线性表的定义和特点

线性表是具有相同特性的数据元素的一个有限序列

n = 0空表

2.3 线性表的类型定义

InitList(&L) 构造一个空的线性表

DestroyList(&L)

ClearList(&L)

ListEmpty(L)

GetElem(L,i,&e) e返回L中第i个元组值

LocateElem(L,e,compare()) 返回第一个与e满足比较的位序

PriorElem(L,cur_e,&pre_e) 返回cur_e的前驱

ListInsert(&L,i,e) 在i位置插入e

ListDelete(&L,i,&e) 删除第i个元素,e返回其值

ListTraverse(&L,visited()) 对表中每个元素调用visited

2.4.1 线性表的顺序存储表示

顺序存储定义:逻辑上相邻,物理上相邻,

LOC(ai) = LOC(a1) + (i - 1)*l

顺序表: 地址连续,随机存取,类型相同,依次存放

线性表长可变,数组长度不可动态定义

#define SIZE 100 //线性表存储空间的初始分配量

数组静态分配:                                          数组动态分配:

typedef struct{                                          typedef struct{

ElemType elem[SIZE];                                   ElemType *elem;

int length;//当前长度                                         int length;

}SqList;                                                   }SqList;

SqList L;//定义变量L,L是SqList 这种类型的,L是个顺序表

L.elem = (ElemType*)malloc (sizeof(ElemType)*SIZE);

多项式的顺序存储结构类型定义

#define MAX 1000

typedef struct{

        float p;//系数

        int e;//指数

}Polynomial;

typedef struct{

        Polynomial *elem;//存储空间的基地址

        int length;//多项式中当前项的个数

}SqList;//多项式的顺序存储结构类型为SqList

图书表的顺序存储结构类型定义

#define MAXSIZE 1000

typedef struct{

        char no[20];//图书ISBN

        char name[50];//图书名字

        float price;//图书价格

}Book;

typedef struct{

        Book *elem;//存储空间的基地址

        int length;//图书表中当前图书个数

}SqList;

Typedef char ElemType;

SqList L;

 L. elem = (ElemType*)malloc (sizeof(ElemType)*SIZE);

malloc(m) :开辟m字节长度的地址空间,并返回这段空间的首地址

sizeof(x):计算x的长度

free(p):释放指针p所指变量的存储空间

C++的动态存储分配:

new 类型名T(处置列表):申请用于存放T类型对象的内存空间,并依初值列表赋以初值

int *p1 = new int;

int *p1 = new int (10);

delete 指针p

C++中的参数传递

实参形参三个一致:类型、个数、顺序

参数传递两种方式:

  1. 传值:
  2. 传地址:参数为指针变量

引用类型

数组名

指针:

void swap(float *m,float *n){     

        float t;

        t = *m;

        *m = *;

        *n = t;

}

main(){

        float a,b,*p1,*p2;

        p1 = &a;

        p2 = &b;

        swap(p1,p2);

}

数组名:作参数传递的是数组的首地址,对形参数组所做的任何改变都将反应到实参数组中

引用类型:共用同一块空间

  1. 传递引用给函数与传递指针效果相同,形参变实参也变
  2. 引用作形参不产生实参副本,直接对实参操作,数据量大时时间空间效率好
  3. 指针参数调用时容易产生错误且程序的阅读性较差

typedef struct{

        ElemType *elem;

        int length;

}SqList;  

SqList L;//定义变量L,L是SqList 这种类型的,L是个顺序表

L.elem[0]

线性表L的初始化(参数用引用)

Status InitList(SqList &L){

        L.elem = new ElemType[MAXSIZE];//为顺序表分配空间

        if(!L.elem) exit (OVERFLOW);

        L.length = 0;

        return OK;

}

销毁线性表L

void DestroyList(SqList &L){

        if(L.elem) delete L.elem;

}

清空

void ClearList(SqList &L){

        L.length = 0;//长度置为0

}

长度

int GetLength(SqList L){

        return L.length;

}

int IsEmpty(SqList L){

        if(L.length==0) return 1;

                else return 0;

}

顺序表取值

int GetElem(SqList L,int i,ElemType &e){

        if(i<1||i>L.length) return ERROR;

        e = L.elem[i-1];

        return OK;

}

顺序表的查找

int LocateElem(SqList L, ElemType e){

        for(i=0;i<L.length;i++)

                if(L.elem[i]==e)  return i+1;

        return 0;

}平均查找长度ASL:Pi*Ci    (n+1)/2

插入算法

Status ListInsert(SqList &L,int i,ElemType e){

        if(i<1||i>L.length+1) return ERROR;//位置合法

        if(L.length==MAXSIZE) return ERROR;

        for(j=L.length-1;j>=i-1;j--)

                L.elem[j+1] = L.elem[j];

        L.elem[i-1] = e;

        L.length++;

        return OK;

}//平均移动次数n/2,时间复杂度O(n)

顺序表的删除

位置合法、元素保留、移动、表长

Status ListDelete(SqList &L,int i){

        if((i<1||(i>L.length))) return ERROR;

        for(j=i;j<=L.length-1;j++)

                L.elem[j-1]=L.elem[j];

        L.length--;

        return OK;

}//平均移动次数(n-1)/2,时间复杂度O(n),空间O(1)

顺序表优点:存储密度大、随机存取

      缺点:插入删除移动大量元素、浪费存储空间、静态存储个数不能自由扩充

2.5线性表的链式表示和实现

单链表由头指针唯一确定,因此单链表可以用头指针的名字来命名,若头指针名是L,则把链表称为表L

结点:

链表:n个结点由指针链组成一个链表

 

头指针:指向链表中第一个结点的指针

首元结点:存储第一个数据元素a1的结点

头结点:在链表的首元节点之前附设的一个结点

 

 2.5.1单链表的定义和表示

typedef struct Lnode{//声明结点的类型和指向结点的指针类型

        ElemType data;

        struct Lnode *next;//结点的指针域

}Lnode,*LinkList;//LinkList为指向结构体Lnode的指针类型

定义链表L: LinkList L;

定义结点指针p: LNode *p;

2.5.2单链表基本操作的实现

单链表的初始化(带头结点)

1.生成新结点作头结点,用头指针L指向头结点

2.将头结点的指针域置空

Status InitList(LinkList &L){

        L = new LNode;//L = (LinkList)malloc(sizeof(LNode));

        L->next = NULL;

        return OK;

}

判断链表为(头结点指针域是否为空)

int ListEmpty(LinkList L){

        if(L->next) return 0;

        else return 1;

}

单链表销毁(从头指针依次释放所有结点)

Status DestroyList(LinkList &L){

        Lnode *p;

        while(L){

                p=L;

                L=L->next;

                delete p;

        }

        return OK;

}

清空链表(头指针头结点仍然在)

Status ClearList(LinkList &L){

        Lnode *p,*q;

        p=L->next;

        while(p){

                q = p->next;

                delete p;

                p = q;

        }

        L->next = NULL;

        return OK;//头结点指针域为空

}

单链表表长(从首元结点依次计数所有结点)

int ListLength(LinkList L){

        LinkList p;

        p=L->next;

        i=0;

        while(p){

                i++;

                p=p->next;

         }

        return i;

}

p=L; p指向头结点

s=L->next; s指向首元节点

取值---取单链表第i个元素的内容

Status GetElem(LinkList L,int i,ElemType &e){

        p=L->next;

        j=1;

        while(p&&j<i){

                p=p->next;

                ++j;

        }

        if(!p||j>i) return ERROR;

        e=p->data;

        return OK;

}

查找

按值查找--数据的地址

Lnode *LocateElem(LinkList L,Elemtype e){

        //查找e,找到返回e的地址

        p=L->next;

        while(p&&p->data!=e)

                p=p->next;

        return p;

}

序号

int LocateElem(LinkList L,Elemtype e){

        //查找e,找到返回e的位置序号

        p=L->next;

        j=1;

        while(p&&p->data!=e){

                p=p->next;

                j++;

        }

        if(p) return j;

        else return 0;

}

插入

Status ListInsert(LinkList &L,int i,ElemType e){

        p=L;

        j=0;

        while(p&&j<i-1){

                p=p->next;

                ++j;

        }

        if(!p||j>i-1) return ERROR;

        s = new LNode;

        s->data = e;

        s->next = p->next;

        p->next = s;

        return OK;

}

删除

Status ListDelete(LinkList &L,int i,ElemType &e){

        p=L;

        j=0;

        while(p->next&&j<i-1){

                p=p->next;

                ++j;

        }

        if(!(p->next)||j>i-1) return ERROR;//删除位置不合理

        q = p->next;

        p->next = q->next;

        e = q->data;

        delete q;

        return OK;

}

1.查找:时间复杂度O(n)

2.插入、删除:一般时间复杂度O(1),前插或删除时间复杂度O(n)

建立单链表:头插法(前插法)

void CreateList(LinkList &L,int n){

        L=new LNode;

        L->next = NULL;//带头结点

        for(i=n;i>0;i--){

                p=new LNode;

                //p = (LNode*)malloc(sizeof(LNode));

                cin>>p->data;

                //scanf(&p->data);

                p->next = L->next;

                L->next = p;

        }

}//时间复杂度:O(n)

尾插法(后插法)

void CreateList(LinkList &L,int n){

        L=new LNode;

        L->next = NULL;//带头结点

        r=L;//尾指针r指向头结点

        for(i=0;i<n;i++){

                p=new LNode;

                cin>>p->data;

                p->next = NULL;

                r->next = p;

                r=p;

        }

}//时间复杂度:O(n)

2.5.3循环链表

循环条件:p!=L

       p->next !=L

尾指针表示单循环链表:a1的存储位置:R->next->next

  an的存储位置:R

  时间复杂度:O(1)

 

带尾指针循环链表的合并(Tb合并在Ta之后)

1.p存表头结点 p = Ta->next;

2.Tb表头连接到Ta表尾 Ta->next = Tb->next->next;

3.释放Tb表头结点 delete Tb->next;

4.修改指针 Tb->next = p;

LinkList Connect(LinkList Ta,LinkList Tb){

        p = Ta->next;

        Ta->next = Tb->next->next;

        delete Tb->next;

        Tb->next = p;

        return Tb;

}//时间复杂度O(1)

2.5.4双向链表

 

结构定义

typedef struct DuLNode{

        Elemtype data;

        struct DuLNode *prior,*next;

}DuLNode,*DuLinkList;

插入删除时间复杂均为:O(n)

双向链表的插入

void ListInsert(DuLinkList &L,int i ,ElemType e){

        //第i位置插入e

        if(!(p=GetElem(L,i))) return ERROR;

        s = new DuLNode;

        s->data = e;

        s->prior = p->prior;

        p->prior->next = s;

        s->next = p;

        p->prior = s;

        return OK;

}

双向链表的删除

void ListDelete_DuL(DuLink &L,int i, ElemType &e){

        if(!(p=GetElemP_Dul(L,i))) return ERROR;

        e = p->data;

        p->prior->next = p->next;

        p->next->prior = p->prior;

        free(p);

        return OK;

}

 

2.6顺序表和链表的比较

 

存储密度:结点数据本身所占用的空间/结点占用的空间总量

2.7线性表的合并

A与B合并成新的集合(无重复)

void union(List &La,List Lb){

        La_len = ListLength(La);

        Lb_len = ListLength(Lb);

        for(i=1;i<Lb_len;i++){

                GetElem(Lb,i,e);

                if(!LocateElem(La,e)) ListInsert(&La,++La_len,e);

        }

}

时间复杂度:O(ListLength(La)*ListLength(Lb))   

  

La、Lb合并成新的Lc   

1.创建空表Lc

2.从La或Lb中取较小的放入Lc表最后

3.将一个表剩余结点插入

  

顺序表实现   

void MergeList_Sq(SqList LA,SqList LB,SqList &LC){

        pa = LA.elem;

        pb = LB.elem;

        //指针pa和pb的初值分别指向两个表的第一个元素

        LC.length = LA.length + LB.length;//新表长度

        LC.elem = new ElemType[LC.length];

        pc = LC.elem;//指针pc指向新表的第一个元素

        pa_last = LA.elem + LA.length-1;//基地址

        pb_last = LB.elem + LB.length-1;

        while(pa<=pa_last&&pb<=pb_last){

                if(*pa<=*pb) *pc++=*pa++;

                else *pc++=*pb++;

        }

        while(pa<=pa_last) *pc++=*pa++;

        while(pb<=pb_last) *pc++=*pb++;

}

时间复杂度:O(ListLength(La)+ListLength(Lb))

空间复杂度:O(ListLength(La)+ListLength(Lb))

  

  

pc->next = pa?pa:pb;

if(pa) pc->next = pa;

else pc->next = pb;   

链表实现   

void MergeList_L(LinkList &La,LinkList n&Lb,LinkList &Lc){

        pa = La->next;

        pb = Lb->next;

        pc=Lc=La;//用La的头结点作为Lc的头结点

        while(pa&&pb){

                if(pa->data<=pb->data){

                        pc->next = pa;

                        pc = pa;

                        pa = pa->next;

                }

                else{

                        pc->next = pb;

                        pc = pb;

                        pb = pb->next;

                }

                pc->next = pa?pa:pb;

                delete Lb;//释放Lb的头结点

        }

}   

时间复杂度:O(ListLength(La)+ListLength(Lb))

空间复杂度:O(1)

多项式相加   

typedef struct PNode{

        float coef;

        int expn;

        struct PNode *next;

}PNode,*Polynomial;

多项式创建

void CreatePolyn(Polynomial &P,int n){

        //建立多项式的有序链表P

        P = new PNode;

        P->next = NULL;//先建立一个带头结点的单链表

        for(i=1;i<=n;++i){

                s = new PNode;

                cin>>s->coef>>s->expn;

                pre = P;//pre用于保存q的前驱,初值为头结点

                q = P->next;//q初始化,指向首元节点

                while(q&&q->expn<s->expn){//找到第一个大于输入项指数的项*q

                pre = q;

                q = q->next;

        }

        s->next = q;//将输入项s插入到q和其前驱结点pre之间

        pre->next = s;

        }

}


struct Book{

        char id[20];

        char name[50];

        int price;

};

typedef struct{//顺序表

        Book *elem;

        int length;

}SqList;

typedef struct LNode{

        Book data;//链表

        struct LNode *next;

}LNode,*LinkList;


 

冒泡:从小到大

C语言

 

‘\0’

 

 

 

三个字符串比较大小:

#include <stdio.h>

#include <string.h>

void cmpswa(char *s1,char *s2)

{

 char d[15];

 strcpy(d,s2);

 strcpy(s2,s1);

 strcpy(s1,d);

}

int main()

{

 char a[15];

 char b[15];

 char c[15];

 printf("请输入三个字符串:");

 scanf("%s%s%s",&a,&b,&c);  

 if(strcmp(a,b)>0) {

  cmpswa(a,b);

 }

 if(strcmp(a,c)>0) {

  cmpswa(a,c);

 }

 if(strcmp(b,c)>0) {

  cmpswa(b,c);

 }

 printf("%s,%s,%s",a,b,c);

 return 0;

}

汉诺塔问题:

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

void move(int x, int y)

{

        printf("%c->%c\n", x, y);

}

void hanoi(int n, char a, char b, char c)

{

        if (n == 1)

        {

                move(a, c);

        }

        else

        {

                hanoi(n - 1, a, c, b);//将A座上的n-1个盘子借助C座移向B座

                move(a, c);//将A座上最后一个盘子移向C座

                hanoi(n - 1, b, a, c);//将B座上的n-1个盘子借助A座移向C座

        }

}

//move中的实参与hanoi函数中的形参相对应,而hanoi函数中形参a,b,c所对应的值也是在有规律的变化

int main()

{

        int n = 0;

        scanf("%d", &n);

        hanoi(n, 'A', 'B', 'C');

        return 0;

}

二维数组必须指定列数

形参第一维大小省略,第二维不能省略,且大小与实参数组第二维大小相同

指针

 

定义指针变量时,左侧应有类型名,否则就不是定义指针变量

Int *p;

 

数组元素的指针:就是数组元素的地址

引用数组元素时指针的运算:

指针已以指向一个数组元素时,可以对指针进行以下运算:

p+1表示指向同一数组中的下一个元素,p-1指向上一个,p++,++p,p--,--p

p1-p2(二者都指向同一数组中的元素),结果是两个地址之差除以数组元素的长度

如果p的初值为&a[0],则p+i和a+i就是数组元素a[i]的地址,

或者说它们指向数组a中序号为i的元素

*(p+i)或*(a+i)是p+i或a+i所指向的数组元素,即a[i]

[]实际是变址运算符,即将a[i]按a+i计算出地址,然后找出此地址单元中的值

p+1,根据定义的基类型加上一个数组元素所占用的字节数

 

 

 

 

 

 

 

 

作业详情

21大数据-线性表1

  • 单选题(共4题,40分)

1. (单选题)1.顺序表中第一个元素的存储地址是100,每个元素的长度为2,则第5个元素的地址是( )。

  • A. 110
  • B. 108
  • C. 100
  • D. 120

我的答案: B正确答案: B

2. (单选题)22.在线性表的下列运算中,不改变数据元素之间结构关系的运算是()。

  • A. 插入
  • B. 删除
  • C. 排序
  • D. 定位

我的答案: D正确答案: D

3. (单选题)顺序表具有随机存取特性指的是( )

  • A. 査找值为x的元素与顺序表中元素的个数n无关
  • B. 查找值为x的元素与顺序表中元素的个数n有关
  • C. 査找序号为i的元素与顺序表中元素的个数n无关
  • D. 査找序号为i的元素与顺序表中元素的个数n有关

我的答案: C正确答案: C

4. (单选题)在n个结点的顺序表中,算法的时间复杂度是O(1)的操作是( )。

  • A. 访问第i个结点(1≤i≤n)和求第i个结点的直接前驱(2≤i≤n)
  • B. 在第i结点后插入一个新结点(1≤i≤n)
  • C. 删除第i个结点(1≤i≤n)
  • D. 将n个结点从小到大排序

我的答案: A正确答案: A

二. 填空题(共4题,40分)

5. (填空题)在有n个元素的顺序表中删除任意一个元素所需移动元素的平均次数为____________我的答案:(1) (n-1)/2正确答案:(1) (n-1)/2;

6. (填空题)在一个长度为n(n≥1)的顺序表中删除第i个元素(1≤i≤n)时需向前移我的答案:(1) n-i 正确答案:(1) n-i;

7. (填空题)在有n个元素的顺序表中的任意位置插为____________入一个元素所需移动元素的平均次数我的答案:(1) n/2正确答案:(1) n/2;

N   n-1 1 0

8. (填空题)6.在长度为n的顺序表中L中将所有值为x的元素替换成y,该算法的时间复杂度为____________

我的答案: (1) O(n) 正确答案:(1) O(n)

三. 判断题(共2题,20分)

9. (判断题)顺序表具有随机存取特性,所以查找值为x的元素的时间复杂度为O(1)。

  • A. 对
  • B. 错

我的答案: 错正确答案: 错

10. (判断题)从长度为n的顺序表中删除任何一个元素所需要的时间均为O(n)。

  • A. 对
  • B. 错

我的答案: 错正确答案: 错

21大数据-链表2

一. 单选题(共9题,90分)

1. (单选题)链表不具有的特点是( )

  • A. 可随机访问任一元素
  • B. 插人、删除不需要移动元素
  • C. 不必事先估计存储空间
  • D. 所需空间与线性表长度成正比

我的答案: A正确答案: A

2. (单选题)当线性表采用链式存储结构时,各结点之间的地址( )

  • A. 必须是连续的
  • B. 一定是不连续的
  • C. 部分地址必须是连续的
  • D. 连续与否均可以

我的答案: D正确答案: D

3. (单选题)

 

17.[2016年第1题】已知表头元素为c的单链表在内存中的存储状态如图2.1所示。现将f存放于1014H处并插入到单链表中,若f在逻辑上位于a和e之间,则a,e,f的“链接地址”依次是( )

  • A. 1010H,1014H,1004H
  • B. 1010H,1004H,1014H
  • C. 1014H,1010H,1004H
  • D. 1014H,1004H,1010H

我的答案: C正确答案: D

4. (单选题)16.[2013年第1题】已知两个长度分别为m和n的升序链表,若将它们合并为一个长度为m+n的降序链表,则最坏情况下的时间复杂度是()。

  • A. O(n)
  • B. O(mxn)
  • C. O(min(m,n))
  • D. O(max(m,n))

我的答案: D正确答案: D

5. (单选题)20.将长度为n的单链表链接在长度为m的单链表之后的算法的时间复杂度为()

  • A. O(1)
  • B. O(n)
  • C. O(m)
  • D. O(m+n)

我的答案: C正确答案: C

6. (单选题)在不带头结点的循环单链表L中,尾结点p的条件是( )

  • A. L!=NULL
  • B. L->next!=L
  • C. p==NULL
  • D. p->next == L

我的答案: D正确答案: D

7. (单选题)2401.在带头结点的循环单链表L中,至少有一个结点的条件是( )

  • A. L->next!=NULL
  • B. L->next!=L
  • C. p==NULL
  • D. p->next==L

我的答案: A正确答案: B

8. (单选题)21.在长度为n(n≥1)的双链表L中,删除p所指结点的时间复杂度为( )

  • A. O(1)
  • B. O(n)
  • C. O(n 2)
  • D. O(nlog 2n)

我的答案: B正确答案: A

9. (单选题)20.在长度为n(n≥1)的双链表L中,删除尾结点的时间复杂度为( )

  • A. O(1)
  • B. O(n)
  • C. O(n 2)
  • D. O(nlog 2n)

我的答案: A正确答案: B

二. 填空题(共1题,10分)

10. (填空题)对于一个具有n(n≥1)个结点的单链表,插入一个尾结点的时间复杂度是____________我的答案:(1) O(1) 正确答案:(1) O(n​​​​​​​

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值