数据结构——线性结构总结

数据结构——线性结构总结

  • 数据结构——线性结构总结
    • 写在前面
    • 线性结构的特点
    • 线性表
    • 队列
    • 相关的STL容器的基本操作
      • vector
      • list
      • stack
      • queue
      • deque
    • 习题
      • 线性表相关——一元多项式的加法和乘法
      • 线性表相关——链表的反转
      • 栈相关——栈的混洗&栈的模拟
    • Reference


写在前面

数据元素的存储(顺序存储和链式存储)和数据元素的操作(插入和删除)是数据结构的重要部分。
数据结构中的线性结构可分为线性表,栈和队列。对于这三种结构,有两种存储方式顺序存储和链式存储以两种主要操作,插入和删除。不同线性结构的插入和删除操作的方式不同,而且不同存储方式在插入和删除的效率上也有所不同。本文就这三种结构x两种存储x两种操作来进行总结,并附上几道相关习题。


线性结构的特点

线性结构的特点是:在数据元素的非空有限集中,
(1)存在惟一的一个被称作“第一个”的数据元素和惟一的一个被称作“最后一个”的数据元素;
(2)除第一个之外,集合中的每个数据元素均只有一个前驱;除最后一个之外,集合中的每一个数据元素均只有一个后继。

线性表

线性表简单来说就是数据元素的非空有限序列,其特点是可以从表中的任何位置进行插入([0 , n])和删除([0 , n-1])操作。本文利用C++实现了线性表的初始化,查找,插入和删除操作,直接附代码如下:

  • 顺序存储
#define MAX_SIZE 100
typedef int ElementType;
typedef struct sqlist{
    ElementType *elem;  //存储空间的基地址
    int length;      //当前长度
    int listsize;     //当前存储空间的大小
}Sqlist;
int init(Sqlist &L) // 初始化
{
    L.elem = (ElementType*)malloc(MAX_SIZE*sizeof(ElementType));
    if(!L.elem) exit(0);
    L.length=0;
    L.listsize = MAX_SIZE;
    return 1;
}
int inser(Sqlist &L, int i, ElementType e) //插入操作
{
    //i的合法值是[0,length]
    //i的意思表示在第i个位置之前插入新元素,i=length时表示在list末尾插入新元素
    if(i<0||i>L.length)return 0;
    if(L.listsize<=L.length)
    {
        ElementType *newbase = (ElementType*)realloc(L.elem,((MAX_SIZE+L.listsize)*sizeof(ElementType)));
        if(!newbase)exit(0);
        L.elem = newbase;
        L.listsize +=MAX_SIZE;
    }
    for(int j=L.length;j>i;j--)L.elem[j]=L.elem[j-1];
    L.elem[i] = e;
    L.length++;
    return 1;
}

int delet(Sqlist &L,int i,ElementType &e)
{
    //删除第i个位置上的元素并用e返回其值
    //i的合法值是[0,length-1]
    if(i<0||i>L.length-1)return 0;
    e = L.elem[i];
    for(int j=i;jlength-1;j++)L.elem[j]=L.elem[j+1];
    L.length--;
    return 1;
}
int cmpEqual(ElementType a, ElementType b)
{
    return a==b;
}
int cmpGreat(ElementType a, ElementType b)
{
    return a>b;
}
int cmpLess(ElementType a, ElementType b)
{
    return aint fin(Sqlist &L, ElementType e,int (*cmp)(ElementType, ElementType))
{
    //查找L中第一个与e满足cmp关系的元素的位序[0,length-1],如果没有则返回-1
    //cmp是比较函数,如果满足cmp的比较条件则返回1,否则返回0
    int i=0;
    for(i=0;ilength;i++)
    {
        if((*cmp)(L.elem[i],e))return i;
    }
    return -1;
}
  • 链式存储
typedef int ElementType;
typedef struct Lnode{
    ElementType data;
    Lnode* next;
}Lnode, *Lnodelist;

void createList(Lnodelist &l,int n)
{
    /*通过控制台的输入,创建大小为n的链表
    两种创建方式,头插法创建的链表和输入顺序相反,尾插法创建的链表和输入顺序相同*/
    l = (Lnode*)malloc(sizeof(Lnode));
    l->next=NULL;
    Lnode *p;
    /*
    Lnode *q = l;
    for(int i=0;i/尾插法
    {
        p = (Lnode*)malloc(sizeof(Lnode));
        cin>>p->data;
        p->next = q->next;
        q->next = p;
        q = p;
    }
    */
    for(int i=n;i>0;i--) //头插法
    {
        p=(Lnode*)malloc(sizeof(Lnode));
        cin>>p->data;
        p->next=l->next;
        l->next = p;
    }
}
int getElem(Lnodelist &l,int i,ElementType&e)
{
    /*返回单链表中第i个元素,i的取值范围是[1,n];*/
    Lnode *p= l->next;
    int j=1;
    while(p&&jnext;
        j++;
    }
    if(!p||j>i)return 0; /*此处判断j>i的原因是,如果传入的i小于1时能够及时报错。*/
    e = p->data;
    return 1;
}
int listInser(Lnodelist &l,int i,ElementType e)
{
    /*在链表第i个位置之前插入元素e,i的取值范围[1, n]*/
    Lnode *p = l,*newP;
    int j=0;
    while(p&&j1)
    {
        p=p->next;
        j++;
    }
    if(!p||j>i-1)return 0; /*此处判断j>i-1的原因是,如果传入的i小于1时能够及时报错。*/
    newP = (Lnode*)malloc(sizeof(Lnode));
    newP->data = e;
    newP->next = p->next;
    p->next = newP;
    return 1;
}
int listDel(Lnodelist &l,int i,ElementType &e)
{
    /*删除链表中第i个元素,并用e返回其值,i的取值范围是[1, n]*/
    Lnode *p= l,*q;
    int j=0;
    while(p->next&&j1)
    {
        p = p->next;
        j++;
    }
    if(!p->next||j>i-1)return 0;/*此处判断j>i-1的原因同上*/
    q = p->next;
    p->next = q->next;
    e =q->data;
    free(q);
    return 1;
}

栈的结构特点是,仅在栈顶(表尾)进行插入和删除操作。栈可以说是操作受限的线性表。栈中元素的修改是按后进先出(LIFO)的原则进行的,所以又称后进先出的线性表。
- 顺序栈

#define STACK_SIZE 100
typedef int SelemType;
typedef struct Stack{
    SelemType *base; //存放数据的数组
    SelemType *top; //栈顶指针,指向栈顶元素上面的地址
    int stacksize; //栈的大小
}Sqstack;
int initS(Sqstack &s)
{
    s.base = (SelemType*)malloc(STACK_SIZE*sizeof(SelemType));
    if(!s.base)exit(0);
    s.top=s.base;
    s.stacksize = STACK_SIZE;
    return 1;
}
int getTop(Sqstack &s,SelemType &e)
{
    //如果不是空栈,则将栈顶元素返回到e,并返回1,否则返回0
    if(s.top==s.base)return 0;
    e = *(s.top-1);
    return 1;
}
int push(Sqstack &s,SelemType e)
{
    //元素e入栈,成功则返回1
    if(s.top-s.base>=s.stacksize)//栈满,追加空间
    {
        s.base = (SelemType*)realloc(s.base,((s.stacksize+STACK_SIZE)*sizeof(SelemType)));
        if(!s.base)exit(0);
        s.top = s.base+s.stacksize; //因为栈数据空间的base指针改变,所以需要更新栈顶top指针;如果top只是一个索引值(整数型),则不必改变。
        s.stacksize +=STACK_SIZE;
    }
    *s.top=e;
    s.top++;
    return 1;
}
int pop(Sqstack &s, SelemType &e)
{
    //若栈不空,则删除栈顶元素,并通过e返回其值,函数返回1,否则,函数返回0
    if(s.top==s.base)return 0;
    s.top--;
    e = *s.top;
    return 1;
}
  • 链栈
    链栈,可以在链表的基础上进行了修改,需要限制插入操作从头插入,删除操作从头删除即可。
typedef struct snode{
    SelemType data;
    struct snode* next;
}*Snode;
typedef struct Lstack{
    Snode stk;
}LStack;
int LinitS(LStack &s)
{
    s.stk = (Snode)malloc(sizeof(struct snode));
    s.stk->next=NULL;
    return 1;
}
int LgetTop(LStack &s,SelemType &e)
{
    //如果不是空栈,则将栈顶元素返回到e,并返回1,否则返回0
    if(s.stk->next==NULL)return 0;
    e = s.stk->next->data;
    return 1;
}
int Lpush(LStack &s,SelemType e)
{
    //元素e入栈,成功则返回1
    Snode newp = (Snode)malloc(sizeof(struct snode));
    if(!newp)exit(0);
    newp->data = e;
    newp->next= s.stk->next;
    s.stk->next = newp;
    return 1;
}
int Lpop(LStack &s, SelemType &e)
{
    //若栈不空,则删除栈顶元素,并通过e返回其值,函数返回1,否则,函数返回0
    if(s.stk->next==NULL)return 0;
    Snode temp = s.stk->next;
    s.stk->next = temp->next;
    e = temp->data;
    free(temp);
    return 1;
}

队列

队列是一种先进先出(FIFO)的线性表,元素从表的一端插入,而从另一端删除。

  • 队列的链式表示
typedef int QElemType;
typedef struct QNode{
    QElemType data;
    struct QNode *next;
}QNode,*Qptr;
typedef struct linkQ{
    Qptr fron;  //队头指针
    Qptr rear;  //队尾指针
}LinkQ;
int InitQ(LinkQ &Q)
{
    //队列初始化为空
    Q.fron =Q.rear = (Qptr)malloc(sizeof(QNode));
    if(!Q.fron)exit(0);
    Q.fron->next=NULL;
    return 1;
}
int DesQ(LinkQ &Q)
{
    //销毁队列Q
    while(Q.fron)
    {
        Q.rear = Q.fron->next;
        free(Q.fron);
        Q.fron = Q.rear;
    }
    return 1;
}
int EnQ(LinkQ &Q,QElemType e)
{
    //入队操作
    Qptr p =(Qptr)malloc(sizeof(QNode));
    if(!p)exit(0);
    p->data = e;
    p->next= Q.rear->next;
    Q.rear->next = p;
    Q.rear=p;
    return 1;
}
int DeQ(LinkQ &Q,QElemType &e)
{
    //出队操作,用e返回其值
    if(Q.fron==Q.rear)return 0;
    Qptr p = Q.fron->next;
    Q.fron->next = p->next;
    e = p->data;
    if(Q.rear==p)Q.rear = Q.fron;
    free(p);
    return 1;
}
  • 队列的顺序表示
    这里利用队列的顺序表示实现了循环队列。
#define MAXQSIZE 10
typedef struct sqQ{
    QElemType *base;
    int fron;
    int rear;
}SqQ;
int SinitQ(SqQ &Q)
{
    //初始化一个空队列
    Q.base = (QElemType*)malloc(MAXQSIZE*sizeof(QElemType));
    if(!Q.base)exit(0);
    Q.fron = Q.rear=0;
    return 1;
}
int Qlen(SqQ &Q)
{
    return (Q.rear-Q.fron+MAXQSIZE)%MAXQSIZE;
}
int SenQ(SqQ &Q,QElemType e)
{
    //插入元素e为Q新的队尾元素
    if((Q.rear+1)%MAXQSIZE ==Q.fron)return 0; //队列满的时候返回0
    Q.base[Q.rear]=e;
    Q.rear = (Q.rear+1)%MAXQSIZE;
    return 1;
}
int SdeQ(SqQ &Q,QElemType &e)
{
    //删除队首元素,用e返回其值
    if(Q.fron==Q.rear)return 0;//队列空的时候返回0
    e = Q.base[Q.fron];
    Q.fron = (Q.fron+1)%MAXQSIZE;
    return 1;
}

相关的STL容器的基本操作

vector

c++ reference
vector是一个能够存放任意类型的动态数组,能够增加和压缩数据。如果向量长度较长(需要为向量内部保存很多数),容易导致内存泄漏,而且效率会很低;Vector作为函数的参数或者返回值时,需要注意它的写法:
double Distance(vector&a, vector&b)
其中的“&”绝对不能少
(1)头文件 #include.
(2)创建vector对象,vector vec;
(3)尾部插入数字:vec.push_back(a);
(4)使用下标访问元素,cout<下标是从0开始的。
(5)使用迭代器访问

vector<int>::iterator it;
for(it=vec.begin();it!=vec.end();it++)
    cout<<*it<

(6)插入元素: vec.insert(vec.begin()+i,a);在第i+1个元素前面插入a;
(7)删除元素:
vec.erase(vec.begin()+2);删除第3个元素
vec.erase(vec.begin()+i,vec.end()+j);删除区间[i,j-1];区间从0开始
(8)向量大小:vec.size();
(9)清空:vec.clear();

list

c++ reference
List是stl实现的双向链表,与向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢。使用时需要添加头文件#include

list<int>lst1;          //创建空list
list<int> lst2(5);       //创建含有5个元素的list
list<int>lst3(3,2);  //创建含有3个元素的list,三个元素的初始值是1
list<int>lst4(lst2);    //使用lst2初始化lst4
list<int>lst5(lst2.begin(),lst2.end());  //同lst4

Lst1.assign() 给list赋值
Lst1.back() 返回最后一个元素
Lst1.begin() 返回指向第一个元素的迭代器
Lst1.clear() 删除所有元素
Lst1.empty() 如果list是空的则返回true
Lst1.end() 返回末尾的迭代器
Lst1.erase() 删除一个元素
Lst1.front() 返回第一个元素
Lst1.get_allocator() 返回list的配置器
Lst1.insert() 插入一个元素到list中
Lst1.max_size() 返回list能容纳的最大元素数量
Lst1.merge() 合并两个list
Lst1.pop_back() 删除最后一个元素
Lst1.pop_front() 删除第一个元素
Lst1.push_back() 在list的末尾添加一个元素
Lst1.push_front() 在list的头部添加一个元素
Lst1.remove() 从list删除元素
Lst1.resize() 改变list的大小
Lst1.reverse() 把list的元素倒转
Lst1.size() 返回list中的元素个数
Lst1.sort() 给list排序

stack

c++ reference
C++ Stack(堆栈) 是一个容器类的改编,为程序员提供了堆栈的全部功能,——也就是说实现了一个先进后出(FILO)的数据结构。
头文件为:
#include
c++ stl栈stack的成员函数介绍
empty() 堆栈为空则返回真
pop() 移除栈顶元素
push() 在栈顶增加元素
size() 返回栈中元素数目
top() 返回栈顶元素

queue

c++ reference
C++队列queue模板类的定义在头文件中,queue 模板类需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque 类型。
C++队列Queue是一种容器适配器,它给予程序员一种先进先出(FIFO)的数据结构。
C++队列Queue类成员函数如下:
back()返回最后一个元素
empty()如果队列空则返回真
front()返回第一个元素
pop()删除第一个元素
push()在末尾加入一个元素
size()返回队列中元素的个数

deque

c++ reference
容器deque和vector非常相似,操作函数基本一致。它采用动态数组来管理元素,提供随机存取,可以在头尾两端进行快速安插和删除元素操作。特别要注意,除了头尾两端,在任何地方安插与删除元素,都将导致指向deque元素的任何pointers references iterators 失效。
包括的头文件为:
#include
构造函数:

deque c   ;  //产生一个空的deque,其中没有任何元素
deque c1(c2); //产生另一个同型deque的副本(所有元素都被拷贝)
deque c(n) ;  //产生一个大小为n的deque
deque c(n , elem) ;  //产生一个大小为n的deque,
                           //每个元素值都是elem。
deque c(begin,end); //产生一个deque,以区间[begin ; end]
                           //做为元素初值

基本操作:

c.size();         //返回当前的元素数量
c.empty();       //判断大小是否为零。等同于c.size() == 0,但可能更快
c.max_size();    //可容纳元素的最大数量
c.at(idx) ;       //返回索引为idx所标示的元素。如果idx越界,抛出out_of_range
c[idx] ;         //返回索引idx所标示的元素。不进行范围检查
c.front() ;       //返回第一个元素,不检查元素是否存在
c.back();        //返回最后一个元素
c.begin();       //返回一个随机迭代器,指向第一个元素
c.end();         //返回一个随机迭代器,指向最后元素的下一位置
c1 = c2  ;        //将c2的所有元素赋值给c1;
c.assign(n , elem);    //将n个elem副本赋值给c
c.assing(beg , end);   //将区间[beg;end]中的元素赋值给c;
c.push_back(elem);   //在尾部添加元素elem
c.pop_back()    ;    //移除最后一个元素(但不回传)
c.push_front()   ;   //在头部添加元素elem
c.pop_front()    ;   //移除头部一个元素(但不回传)
c.erase(pos)    ;   //移除pos位置上的元素,返回一元素位置
                  //如 c.erase( c.begin() + 5)  //移除第五个元素
c.insert(pos , elem); //在pos位置插入一个元素elem,并返回新元素的位置
c.insert(pos , n , elem); //在pos位置插入n个元素elem,无返回值
c.insert(pos , beg , end);
c.resize(num);       //将容器大小改为num。可更大或更小。
c.resize(num , elem);  //将容器大小改为num,新增元素都为 elem
c.clear();            //移除所有元素,将容器清空

习题

线性表相关——一元多项式的加法和乘法

题目描述

输入格式 输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。

输出格式 输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。零多项式应输出0 0。
输入样例
4 3 4 -5 2 6 1 -2 0
3 5 20 -7 4 3 1
输出样例
15 24 -25 22 30 21 -10 20 -21 8 35 6 -33 5 14 4 -15 3 18 2 -6 1
5 20 -4 4 -5 2 9 1 -2 0
(题目选自PTA,作者: 浙江大学DS课程组)

题解

//节点数据类型
typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
    ElementType Data;
    ElementType exponent;
    PtrToNode   Next;
};

加法依次计算即可,注意系数data为零时需要删除节点;
乘法转换为加法计算,即让其中一个表达式的每一项依次与另一个多项式相乘,然后相加并合并同类项,注意系数为零的情况,注意插入位置的选择,需要遍历结果链表,选择合适的插入位置。
具体代码C语言如下

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

typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
    ElementType Data;
    ElementType exponent;
    PtrToNode   Next;
};
//头结点的data存放多项式的项数
typedef PtrToNode List;

List Read(int n);
void Print( List L );
List multi(List L1,List L2);
List add( List L1, List L2 );

int main()
{
    List L1, L2;
    int n1,n2;
    scanf("%d",&n1);
    L1 = Read(n1);
    scanf("%d",&n2);
    L2 = Read(n2);
    Print(L1);
    Print(L2);
    List La;
    List Lm;
    Lm = multi(L1,L2);
    La = add(L1, L2);
    Print(Lm);
    Print(La);



    return 0;
}

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

List Read(int n)
{
    List l = (List)malloc(sizeof(struct Node));
    l->Data = n;
    PtrToNode p = l;
    p->Next = NULL;
    ElementType res_data,res_exponent;
    while(n--)
    {
        scanf("%d %d",&res_data,&res_exponent);
        PtrToNode new_p = (PtrToNode)malloc(sizeof(struct Node));
        new_p->Data = res_data;
        new_p->exponent = res_exponent;
        new_p->Next = NULL;
        p->Next = new_p;
        p = new_p;
    }
    return l;
}

List add(List L1, List L2)
{
    List r = (List)malloc(sizeof(struct Node));
    PtrToNode p = r,p1,p2,pre1,pre2;
    int num = 0;
    if(!L1)
    {
        return L2;
    }
    if(!L2)
    {
        return L1;
    }
    pre1 = L1->Next;
    pre2 = L2->Next;
    p1 = L1->Next;
    p2 = L2->Next;
    while(p1&&p2)
    {
        if(p1->exponent==p2->exponent)
        {
            PtrToNode new_p = (PtrToNode)malloc(sizeof(struct Node));
            if(p1->Data+p2->Data!=0)
            {
                new_p->Data = p1->Data + p2->Data;
                new_p->exponent = p1->exponent;
                new_p->Next = NULL;
                p->Next = new_p;
                p=new_p;
                num++;
            }
            p1=p1->Next;
            p2=p2->Next;
            free(pre1);
            free(pre2);
            pre1 = p1;
            pre2 = p2;

        }
        else if(p1->exponent>p2->exponent)
        {
            PtrToNode new_p = (PtrToNode)malloc(sizeof(struct Node));
            new_p->Data = p1->Data;
            new_p->exponent = p1->exponent;
            new_p->Next = NULL;
            p->Next = new_p;
            p=new_p;
            num++;
            p1=p1->Next;
            free(pre1);
            pre1 = p1;
        }
        else if(p1->exponent<p2->exponent)
        {
            PtrToNode new_p = (PtrToNode)malloc(sizeof(struct Node));
            new_p->Data = p2->Data;
            new_p->exponent = p2->exponent;
            new_p->Next = NULL;
            p->Next = new_p;
            p=new_p;
            num++;
            p2=p2->Next;
            free(pre2);
            pre2 = p2;
        }
    }
    while(p1)
    {
        PtrToNode new_p = (PtrToNode)malloc(sizeof(struct Node));
        new_p->Data = p1->Data;
        new_p->exponent = p1->exponent;
        new_p->Next = NULL;
        p->Next = new_p;
        p=new_p;
        num++;
        p1=p1->Next;
        free(pre1);
        pre1 = p1;
    }
    while(p2)
    {
        PtrToNode new_p = (PtrToNode)malloc(sizeof(struct Node));
        new_p->Data = p2->Data;
        new_p->exponent = p2->exponent;
        new_p->Next = NULL;
        p->Next = new_p;
        p=new_p;
        num++;
        p2=p2->Next;
        free(pre2);
        pre2 = p2;
    }
    r->Data = num;
    return r;
}
List multi(List L1,List L2)
{
    List r = (List)malloc(sizeof(struct Node));
    int num_item = 0;
    PtrToNode now_ptr = r,p1 = L1->Next,p2 = L2->Next;
    if(!p1||!p2)
    {
        r->Data = 0;
        r->Next = NULL;
        return r;

    }
    while(p2)
    {
        PtrToNode new_node = (PtrToNode)malloc(sizeof(struct Node));
        new_node->Data = p1->Data*p2->Data;
        new_node->exponent = p1->exponent+p2->exponent;
        new_node->Next = NULL;
        now_ptr->Next = new_node;
        now_ptr = now_ptr->Next;
        num_item++;
        p2=p2->Next;
    }
    p1=p1->Next;
    while(p1)
    {
        p2 = L2->Next;
        now_ptr = r;
        while(p2)
        {
            ElementType e = p1->exponent + p2->exponent;
            ElementType num = p1->Data*p2->Data;
            while(now_ptr->Next&&now_ptr->Next->exponent>e)
            {
                now_ptr = now_ptr->Next;
            }
            if(now_ptr->Next&&now_ptr->Next->exponent==e)
            {
                if((now_ptr->Next->Data+num)!=0)
                {
                    now_ptr->Next->Data+=num;
                }
                else
                {
                    PtrToNode temp = now_ptr->Next;
                    now_ptr->Next = temp->Next;
                    free(temp);
                    num_item--;
                }
            }
            else
            {
                PtrToNode new_node = (PtrToNode)malloc(sizeof(struct Node));
                new_node->Data = num;
                new_node->exponent = e;
                new_node->Next = now_ptr->Next;
                now_ptr->Next = new_node;
                now_ptr = now_ptr->Next;
                num_item++;
            }
            p2=p2->Next;
        }
        p1 = p1->Next;
    }
    r->Data = num_item;
    return r;
}

线性表相关——链表的反转

//链表反转函数详解
 node* reverseList(node* H) { 
if (H == NULL || H->next == NULL) //链表为空或者仅1个数直接返回 return H;
node* p = H, *newH = NULL;
while (p != NULL) //一直迭代到链尾 {
node* tmp = p->next; //暂存p下一个地址,防止变化指针指向后找不到后续的数
p->next = newH; //p->next指向前一个空间
newH = p; //新链表的头移动到p,扩长一步链表 
p = tmp; //p指向原始链表p指向的下一个空间 
} 
return newH;

//C++库函数
#include<algorithm>
reverse(first ptr,last ptr);//这个函数反转了[first,last)之间的节点(一些容器也有reverse函数,可直接使用)
}

栈相关——栈的混洗&栈的模拟

题目描述

Given a stack which can keep M numbers at most. Push N numbers in the order of 1, 2, 3, …, N and pop randomly. You are supposed to tell if a given sequence of numbers is a possible pop sequence of the stack. For example, if M is 5 and N is 7, we can obtain 1, 2, 3, 4, 5, 6, 7 from the stack, but not 3, 2, 1, 7, 5, 6, 4.

Input Specification:
Each input file contains one test case. For each case, the first line contains 3 numbers (all no more than 1000): M (the maximum capacity of the stack), N (the length of push sequence), and K (the number of pop sequences to be checked). Then K lines follow, each contains a pop sequence of N numbers. All the numbers in a line are separated by a space.

Output Specification:
For each pop sequence, print in one line “YES” if it is indeed a possible pop sequence of the stack, or “NO” if not.
Sample Input:
5 7 5
1 2 3 4 5 6 7
3 2 1 7 5 6 4
7 6 5 4 3 2 1
5 6 4 3 7 2 1
1 7 6 5 4 3 2
Sample Output:
YES
NO
NO
YES
NO
(problem source:PTA DS course)

题解
直接模拟这样一种栈混洗的过程,建立三个栈,先后完成push()…pop()…push()的操作,保证能依次得到目标序列,那么就可以确定这样的序列是可以得到的,反之就不能得到,这样的时间度最小为O(n)。

#include 
#include
using namespace std;

bool judge(int m,int n, int b[])
{
    stack<int>a;
    stack<int>s; //使用两个栈来模拟操作过程
    for(int i=n;i>=1;i--)
    {
        a.push(i);
    }
    int i=0;
    while(iint top = b[i];
        if(!a.empty()&&a.top()==top)
        {
            int temp=a.top();
            a.pop();
            s.push(temp);
            if((int)s.size()>m)
            {
                return false;
            }
            s.pop();
            i++;
        }
        else if(!s.empty()&&s.top()==top)
        {
            s.pop();
            i++;
        }
        else
        {
            if(a.empty())
            {
                return false;
            }
            int temp = a.top();
            a.pop();
            s.push(temp);
            if(a.empty()||(int)s.size()>m)
            {
                return false;
            }
        }
    }
    if(a.empty()&&s.empty())
    {
        return true;
    }
    return false;

}

int main()
{
    int m,n,k;
    cin>>m>>n>>k;
    bool res[k];
    int b[n];
    for(int i=0;ifor(int j=0;jcin>>b[j];
        }
        res[i] = judge(m,n,b);
    }
    for(int i=0;iif(res[i])
        {
            cout<<"YES"<else
        {
            cout<<"NO"<

Reference

  • 数据结构(C语言版) 严蔚敏 清华大学出版社
  • http://www.cplusplus.com/reference/
  • https://blog.csdn.net/yas12345678/article/details/52601578
  • https://blog.csdn.net/duan19920101/article/details/50617190/

你可能感兴趣的:(数据结构DS)