陈越《数据结构》第二章 线性结构

2.1 线性表


2.1.1 基本知识


例1:一元多项式及其运算
f(x)=a0+a1x....+an1xn1+anxn
表示方法:
1. 顺序存储结构直接表示;
2. 顺序存储 结构;
(用结构数组表示:数组分量是由系数 ai 、指数 i 组成的结构,对应一个非零项)
3. 链表结构存储非零项。
(链表中每个结点存储多项式中的一个 非零项,包括:系数和指数 两个数据域以及一个。)
这里写图片描述

启示

  1. 同一个问题可以有不同的表示(存储)方法;
  2. 有一类共性问题:有序线性序列的组织和管理。

线(定义时:1.数据对象集和操作集)
定义:由同类型 数据元素 构成的 有序序列 的 线性结构。

  1. 表中元素个数称为线性表的 长度
  2. 线性表没有元素时,称为 空表
  3. 表起始位置称 表头,表结束位置称 表尾

解析:



看看上面三个表达式分别是什么意思?

A) char *(*fun1)(char *p1,char *p2);
B) char **fun2(char *p1,char *p2);
C) char *fun3(char *p1,char *p2);

答:
C)这很容易,fun3是函数名,p1,p2是参数,其类型为char 型,函数的返回值为char 类型。

B) 也很简单,与C)表达式相比,唯一不同的就是函数的返回值类型为char**,是个二级指针。

A) fun1是函数名吗?回忆一下前面讲解数组指针时的情形。我们说数组指针这么定义或许更清晰:
int()[10]p;
再看看A)表达式与这里何其相似!明白了吧。这里fun1不是什么函数名,而是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。同样,我们把这个表达式改写一下:
char()(charp1,charp2)fun1;
这样子是不是好看一些呢?只可惜编译器不这么想。
来源于.


structtypedefstruct
1 首先://注意在C和C++里不同
    在C中定义一个结构体类型要用typedef:
    typedef struct Student{
    int a;
    }Stu;
  于是在声明变量的时候就可:Stu stu1;(如果没有typedef就必须用struct Student stu1;来声明)
  这里的Stu实际上就是struct Student的别名。Stu==struct Student
  另外这里也可以不写Student(于是也不能struct Student stu1;了,必须是Stu stu1;)
    typedef struct{
    int a;
    }Stu;
    但在c++里很简单,直接
    struct Student{
    int a;
    };    
 于是就定义了结构体类型Student,声明变量时直接Student stu2;
 
2.其次:在c++中如果用typedef的话,又会造成区别:
    struct Student {
    int a;
    }stu1;//stu1是一个变量
    typedef struct Student2 {
    int a;
    }stu2;//stu2是一个结构体类型=struct Student
   使用时可以直接访问stu1.a
  但是stu2则必须先 stu2 s2;
  然后 s2.a=10;

3. 给出一个实例
typedef struct tagMyStruct{
     int iNum;
     long lLength;
    } MyStruct;
  C
    (1) struct tagMyStruct 变量名;
    (tagMyStruct称为”tag”,即”标签”,实际上是一个临时名字,不论是否有typedefstruct 关键字和tagMyStruct一起,构成了这个结构类型,这个结构都存在。)
    (2) MyStruct 变量名
     c++
    (1) struct tagMyStruct 变量名
    (2) MyStruct 变量名
    (3) tagMyStruct 变量名
来源于。



Qus:
typedef struct{
ElementType Data[MAXSIZE];
int Last;
} List;
List L, *PtrL;
然后是初始化的
1. 初始化(建立空的顺序表)
List *MakeEmpty( )
{ List *PtrL;
PtrL = (List *)malloc( sizeof(List) );
PtrL->Last = -1;
returnPtrL;
}

初始化空的列表直接给他List L, *PtrL;把指针赋过去不就好了吗,为什么还要搞出MakeEmpty( )啊?

Ans:
MakeEmpty( )完成的工作:
1、动态申请了顺序表的空间;
2、设置表指针为-1;
3、返回了表的指针;
你的操作 List L, *PtrL;
PtrL = &L;
L.Last = -1;
来源于。


2.1.2 顺序存储


  1. 定义:利用数组的 连续存储空间顺序存放 线性表的各元素。
    这里写图片描述

各种操作的时间性能:
1. 查找 O(k) ;
2. 插入 O(n) ;
这里写图片描述
3. 删除 O(n) ;
这里写图片描述

2.1.3 链式存储


定义:
这里写图片描述
结构的定义:
引用块内容

基本操作:
1. 求表长,时间性能为 O(n)。
2. 查找,按序号查找: FindKth 和 按值查找: Find,时间性能为 O(n)。
3. 插入,时间性能为 O(n)。
这里写图片描述
4. 删除,时间性能为 O(n)。
这里写图片描述


2.1.4 广义表和多重链表


2.1.4.1 广义表

这里写图片描述


2.1.4.2 多重链表

这里写图片描述

例子:表示稀疏矩阵
这里写图片描述


2.2 堆栈


2.2.1堆栈定义和堆栈的抽象数据类型

例1:中缀表达式 a+bcd/e ,请问前缀表达式和后缀表达式是什么?

  • 前缀表达式: +abcd/e ;
  • 后缀表达式: abc+de/ .
    如果用后缀表达式来进行计算,实质就是堆栈的应用!

堆栈定义:
具有一定 操作约束 的 线 只在 ( 栈顶 ,Top )做
这里写图片描述

例2:如果 三 个字符 按 ABC 顺序压入堆栈:
ABC 的所有排列都可能是出栈的序列 吗 ?
• 可以产生 CAB 这样的序列吗?
这里写图片描述


2.2.2 顺序存储


例3:请用一个数组实现两个堆栈,要求最大地利用数组空间,使数组只要有空间入栈操作就可以成功。

解析
一种比较聪明的方法是使这两个栈分别从数组的 两头开始向中间生长;当两个栈的 栈顶指针相遇 时,表示两个栈都满了。
这里写图片描述


2.2.3 堆栈的链式存储及应用


链式存储定义:
栈的链式存储结构 实际上就是 一个 单链表,叫做 链栈 。插入和删除操作只能在链栈的栈顶进行。 Top

:栈顶放在链表的表头,放在尾部不行!

应用: :中缀表达式求值。
基本策略:将中缀表达式转换为后缀表达式,然后求值,如何将中缀表达式转换为后缀?

步骤:
这里写图片描述

堆栈的其他应用:
1. 函数调用及递归实现
2. 深度优先搜索
3. 回溯算法
….


2.3 队列


2.3.1 定义及顺序存储


1.定义: FIFO
这里写图片描述

这里写图片描述

这里写图片描述

2.队列的顺序存储
例1:队列 的顺序存储结构通常由一个 一维数组 和一个记录 队列头 元素位置的变量front 以及 一个记录 队列尾 元素位置的变量rear 组成。

为了抑制 现象,我们用循环队列进行模拟,但是会出现“空”和“满”无法判断的情况,我们运用:
1. 另设变量;Size(计算队列内元素个数)和tag(标记队列中是否有元素);
2. 少用一个空间元素。
:通常用求余方法进行求解(%)。


2.3.2队列的链式存储

定义:
队列 的 链式 存储结构 也可以用 一个 单链表 实现。插入和删除操作分别在链表的两头进行;队列指针 front rear 应该分别指向 链表的 哪一 头 ?

答:
front 单链表表头, rear 单链表表尾。

这里写图片描述

例1:如何用两个栈模拟实现一个队列? 如果这两个堆栈的容量分别是m和n(m>n),你的方法能保证队列的最大容量是多少?(这里讨论的是顺序栈,如果是链式栈的话完全没有必要考虑空间)
答:
:用一个栈作为存储空间,另一个栈作为输出缓冲区,入队时把元素按顺序压入两栈模拟的队列,出队时按入队的顺序出栈即可。
:两个栈所模拟的队列的最大容量为2n+1。


2.4 应用实例及小白专场


多项式的加法和乘法:
这里写图片描述

//author: Paul_Huang
//Data: 15/6/2017

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

typedef struct PolyNode *Polynomial;
struct PolyNode{
    int coef;   //系数
    int expon;  //指数
    struct PolyNode *link;  //指向下一个节点的指针
};
Polynomial P1,P2;

Polynomial ReadPoly();
void Attach(int coeff, int expon, Polynomial *pRear);
Polynomial PolyAdd(Polynomial P1, Polynomial P2);
Polynomial PolyMulti(Polynomial P1,Polynomial P2);
void PrintPoly(Polynomial P);   //输出多项式

int main()
{
    Polynomial P1,P2,PP,PS;

    P1 = ReadPoly();    
    P2 = ReadPoly();
    PP = PolyMulti(P1,P2);
    PrintPoly(PP);
    PS = PolyAdd(P1,P2);
    PrintPoly(PS);
    system("pause");//暂停往下执行 按下任意键继续
    return 0;

}

Polynomial ReadPoly()
{
    int i;
    int coeff,expon;
    Polynomial first,rear,temp;
    /*input count number*/
    scanf("%d",&i);
    first = (Polynomial) malloc(sizeof(struct PolyNode));
    first->link = NULL;
    rear = first;
    /*read the Poly*/
    while(i--)
    {
        scanf("%d %d",&coeff,&expon);
        Attach(coeff,expon,&rear);
    }
    temp = first; first = first->link; free(temp);
    return first;
}

void Attach(int coeff, int expon, Polynomial *pRear)
{
    Polynomial P;

    P = (Polynomial) malloc(sizeof(struct PolyNode));
    P->coef = coeff;
    P->expon = expon;
    P->link = NULL;
    /*将P指针指向新节点*/
    (*pRear)->link = P;
    *pRear = P;
}

Polynomial PolyAdd(Polynomial P1, Polynomial P2)
{
    Polynomial front,rear,temp;
    int sum;
    front = (Polynomial) malloc(sizeof(struct PolyNode));   //链表附加头结点
    front->link = NULL;
    rear = front;

    while(P1&&P2)
    {
        if(P1->expon == P2->expon)
        {
            sum = P1->coef + P2->coef;
            if(sum) Attach(sum,P1->expon,&rear);
            P1 = P1->link;
            P2 = P2->link;
        }
        else if(P1->expon > P2->expon)
        {
            Attach(P1->coef,P1->expon,&rear);
            P1 = P1->link;
        }
        else
        {
            Attach(P2->coef,P2->expon,&rear);
            P2 = P2->link;
        }
    }
    /*  将未处理完的另一个多项式的所有节点依次复制到结果多项式中去  */
    for(;P1;P1=P1->link)    Attach(P1->coef,P1->expon,&rear);
    for(;P2;P2=P2->link)    Attach(P2->coef,P2->expon,&rear);

    temp = front;front = front->link; free(temp);
    return front;
}

Polynomial PolyMulti(Polynomial P1,Polynomial P2)
{
    Polynomial front,rear,temp,sP2;
    int coeff = 0,expon = 0;
    if(!P1||!P2)    return NULL;        //先对其进行验证;

    front = (Polynomial) malloc(sizeof(struct PolyNode));
    front->link = NULL;
    rear = front;
    sP2 = P2;
    /*先准备第一列。对其进行对比*/
    while(P2)
    {
        Attach(P1->coef * P2->coef , P1->expon + P2->expon , &rear);
        P2 = P2->link;
    }
    /*以下加上去的项是由上面的项进行比较*/
    P1 = P1->link;
    while(P1)
    {
        P2 = sP2;           //恢复P2初始位置
        rear = front;       //从表头开始扫描结果多项式链表
        while(P2)
        {
            coeff = P1->coef * P2->coef;
            expon = P1->expon + P2->expon;
            while(rear->link && rear->link->expon > expon)  //结果多项式链表中的数据项指数较大
            {
                rear = rear->link;
            }
            if(rear->link && (rear->link->expon ==expon))   //两数据项指数相等
            {
                if(rear->link->coef + coeff)        //系数和非0
                {
                    rear->link->coef +=coeff;
                }
                else                //系数和为0,需要在结果多项式链表中删除次表项
                {
                    temp = rear->link;
                    rear->link = temp->link;
                    free(temp);
                }
            }
            else                 //结果多项式链表中的数据项指数较小
            {
                temp = (Polynomial) malloc(sizeof(struct PolyNode));
                temp->coef = coeff;
                temp->expon = expon;
                temp->link = rear->link;    //把新表项插入到结果多项式链表中
                rear->link = temp;
                rear = rear->link;
            }
            P2 = P2->link;
        }
        P1 = P1->link;
    }
    temp = front;front = front->link;free(temp);
    return front;
}

void PrintPoly(Polynomial P)    //输出多项式
{
    int flag=0;        //输出序号,用来辅助调整输出格式
    if(!P){ printf("0 0\n"); return;}  //当多项式链表为空

    while(P)
    {
        if(!flag)    flag=1;  //第一次输出,没有前置空格
        else   printf(" ");   //输出前置空格
        printf("%d %d",P->coef,P->expon);
        P = P->link;
    }
    printf("\n");
}

这里写图片描述

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

typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
    ElementType Data;
    PtrToNode   Next;
};
typedef PtrToNode List;

List Read(); /* 细节在此不表 */
void Print( List L ); /* 细节在此不表;空链表将输出NULL */

List Merge( List L1, List L2 );

int main()
{
    List L1, L2, L;
    L1 = Read();
    L2 = Read();
    L = Merge(L1, L2);
    Print(L);
    Print(L1);
    Print(L2);
    system("pause");//暂停往下执行 按下任意键继续
    return 0;
}

List Read()
{
    int i , coeff;
    PtrToNode first , rear , temp;
    /*input count number*/
    scanf("%d",&i);
    if(i == 0)
       return NULL;
    /*initialization*/
    first = (PtrToNode) malloc(sizeof(struct Node));
    first->Next = NULL;
    rear = first;
    /*get number*/
    while(i--)
    {
        temp = (PtrToNode) malloc(sizeof(struct Node));
        scanf("%d",&coeff);
        temp->Data = coeff;
        rear->Next = temp;
        rear = temp;
        /*free(temp);*/
    }
    temp = first; first = first->Next; free(temp);
    rear->Next = NULL;
    return first;
}

void Print(List L)
{
    int flag = 0;
    if(!L)
    {
        printf("NULL\n");
        return;
    }
    while(L)
    {
        printf("%d ",L->Data);
        L = L->Next;
    }
    printf("\n");
}

List Merge( List L1, List L2 )
{
    PtrToNode front,rear,temp;
    //int coeff;
    /*初始化链表*/
    front = (PtrToNode) malloc(sizeof(struct Node));
    front->Next = NULL;
    rear = front;

    while(L1&&L2)
    {
        if(L1->Data <= L2->Data)
        {
            temp = (PtrToNode) malloc(sizeof(struct Node));
            temp->Data = L1->Data;
            rear->Next = temp;
            rear = temp;
            L1 = L1->Next;      
        }
        else
        {
            temp = (PtrToNode) malloc(sizeof(struct Node));
            temp->Data = L2->Data;
            rear->Next = temp;
            rear = temp;
            L2 = L2->Next;
        }
    }
     while(L1)
     {  
        temp = L1;  
        rear->Next = temp;
        rear = temp; 
        L1=L1->Next;  
    }  
    while(L2)
    {  
        temp = L2;  
        rear->Next = temp;
        rear = temp;
       L2 = L2->Next;   
    }
    temp = front; front = front->Next;free(temp);
    L1->Next=NULL;  
    L2->Next=NULL;      
    return front;
}
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值