01--基础与线性表

[toc]

数据结构

是一门独立的学科, 也可以看出它在计算机专业的地位. 它不是算法的附属品. 好的程序数据结构设计 = 数据结构 + 算法.

数据结构核心名称解释

  • 数据 :程序的操作对象,用于描述客观事物.
    • 可以输入到计算机
    • 可以被计算机处理
  • 数据对象:一个数据元素由若干数据项组成
  • 数据元素 :组成数据对象的基本单位
  • 数据项 :性质相同的数据元素的集合(类似于数组)
  • 结构: 数据元素之间不是独立的,存在特定的关系.这些关系即是结构;
  • 数据结构:指的数据对象中的数据元素之间的关系

举例子:

  • struct Teacher为一种数据结构,里面申明的变量为数据项
//声明一个结构体类型
struct Teacher{     //一种数据结构
    char *name;     //数据项--名字
    char *title;    //数据项--职称
    int  age;       //数据项--年龄
};
  • 声明一个类型为Teacher的结构体变量T1,此时T1就是数据元素
  • 如果把多个数据元素放在一个数组中,数组就成为数据组对象
 struct Teacher t1;     //数据元素;
    struct Teacher tArray[10]; //数据对象;
    
    t1.age = 18;       //数据项
    t1.name = "teacher";    //数据项
    t1.title = "教师";  //数据项

关系图

  • 数据对象包含数据元素,数据元素含义数据项
  • 数据对象也属于一种数据


    image.png

逻辑结构和物理结构区别

逻辑结构

  • 集合结构
    • 数据属于同一个集合,之前没有先后顺序.
  • 线性结构
    • 线性表 队列 栈 数组
    • 数组1对1
    • 队列 栈特殊线性结构,在于读取方式,一个先进先出,一个先进后出.
    • 字符串也属于,是由一个个字符拼接的
  • 树形结构
    • 1对多,属于一对多都属于树形结构.
    • 不包括线性结构.
  • 图形结构
    • 多对多

物理结构

  1. 逻辑结构

数据与数据之前的逻辑关系,这些最终要物理结构存储到内存空间,内存空间存储.

  1. 物理结构
  • 顺序存储,缺点插入比较耗时.插入线位移,在插入.

3 . 链式存储

  • 有几个数开辟几个空间,不需要提前开启很多空间.
  • 插入找到为位置就行,缺点结构很大,查询起来麻烦.

算法时间复杂度计算

数据结构和算法是不可分割,算法是解决问题,解决问题需要数据.

image.png

算法定义

算法就是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列列, 并且每个指令表示⼀一个或多个操作.

算法的特性

  • 输⼊入输出
  • 有穷性
  • 确定性
  • 可行性

算法设计要求

  • 正确性
  • 可读性
  • 健壮性
  • 时间效率⾼高和储存量量低

算法时间复杂度

  • 算法输入时间
  • 编译执行时间
  • 执行命令
  • 执行重复命令
大O表示法
  1. 用常数1取代运行时间中所有常数3->1 O(1)
  2. 在修改运行次数函数中,只保留最高阶项n^3+2n^2+5 -> O(n^3)
  3. 如果在最高阶存在且不等于1,则去除这个项目相乘的常数 2n^3 -> n^3
时间复杂度常用术语
  • 常数阶

1+1+1 = 3 O(1)函数执行时间和n无关

 void testSum1(int n){
    int sum = 0;                //执行1次
    sum = (1+n)*n/2;            //执行1次
    printf("testSum1:%d\n",sum);//执行1次
}

1+1+1+1+1+1+1 = 7 O(1) 代码执行固定,不会变

void testSum2(int n){
    int sum = 0;                //执行1次
    sum = (1+n)*n/2;            //执行1次
    sum = (1+n)*n/2;            //执行1次
    sum = (1+n)*n/2;            //执行1次
    sum = (1+n)*n/2;            //执行1次
    sum = (1+n)*n/2;            //执行1次
    printf("testSum2:%d\n",sum);//执行1次
    
}

  • 线性阶

函数执行次数有n决定,所以是线性级,所以时间复杂度 O(n)

void add2(int x,int n){
    for (int i = 0; i < n; i++) {
        x = x+1;
    }
}

1+(n+1)+n+1 = 3+2n -> 保留最高阶 O(n)

void testSum3(int n){
   int i,sum = 0;               //执行1次
   for (i = 1; i <= n; i++) {   //执行n+1次
       sum += i;                //执行n次
   }
   printf("testSum3:%d\n",sum);  //执行1次
}
  • 平方阶

x=x+1; 执行n*n次 ->O(n^2)

void add3(int x,int n){
   for (int i = 0; i< n; i++) {
       for (int j = 0; j < n ; j++) {
           x=x+1;
       }
   }
}

1+(n+1)+n(n+1)+n2+n2 = 2+3n^2+2n -> O(n^2)


void testSum5(int n){
   int i,j,x=0,sum = 0;           //执行1次
   for (i = 1; i <= n; i++) {     //执行n+1次
       for (j = 1; j <= n; j++) { //执行n(n+1)
           x++;                   //执行n*n次
           sum = sum + x;         //执行n*n次
       }
   }
   printf("testSum5:%d\n",sum);
}
  • 对数阶

观察值当2的n吃饭不小于n循环结束

2的x次方等于n x = log2n ->O(logn)

因为
image.png

代入则
image.png

image.png
void testA(int n){
   int count = 1;         //执行1次
   //n = 10
   while (count < n) {
       count = count * 2;
   }
   
}

  • 立方阶
void testB(int n){
   int sum = 1;                         //执行1次
   for (int i = 0; i < n; i++) {        //执行n次
       for (int j = 0 ; j < n; j++) {   //执行n*n次
           for (int k = 0; k < n; k++) {//执行n*n*n次
               sum = sum * 2;          //执行n*n*n次
           }
       }
   }
}
  • nlog阶
    • 后面再讲
  1. 指数阶(不考虑) O(2^n)或者O(n!)除非是非常小的n,否则会造成噩梦般的时间消耗. 这是一种不切实际的算法时间复杂度. 一般不考虑!
图示
image.png
空间复杂度

算法的空间复杂度通过计算算法所需的存储空间实现,算法空间复杂度的计算公式 记做: S(n) = n(f(n)),其中,n为问题的规模,f(n)为语句句关于n所占存储空间的函数

  • 主要考虑算法执行时所需要的辅助空间

开辟一个空间 o(1)

算法实现(1)
   int temp;   
   for(int i = 0; i < n/2 ; i++){
       temp = a[I];
       a[i] = a[n-i-1];
       a[n-i-1] = temp;
   }

开辟空间去决定n O(n)

int b[10] = {0};
   for(int i = 0; i < n;i++){
       b[i] = a[n-i-1];
   }
   for(int i = 0; i < n; i++){
       a[i] = b[I];
   }
image.png

线性表 顺序表

  • 对于⾮非空的线性表和线性结构,其特点如下:
  1. 线性表:零个或者多个数据元素的有限序列。元素之间是有序的,若元素存在多个,则第一个元素无前驱,最后一个元素无后继。线性表是有限的)
  2. 线性表的个数定义为线性表的长度 个数为0即是空表。

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

  • 线性表的顺序存储结构: 指的是用一段地址连续的存储单元依次存储线性表的数据元素。

图示


image.png

顺序存储

声明一下宏定义,结构体
#define MAXSIZE 100
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

/* ElemType类型根据实际情况而定,这里假设为char */
typedef char ElemType;
/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Status;

/*线性结构使用顺序表的方式存储*/
typedef struct{
    ElemType *data;
    int length;
    
}Sqlist;
顺序表初始化
Status InitList(Sqlist *L){
    //为顺序表分配一个大小为MAXSIZE 的数组空间
    // L->data指向首地址
    L->data = malloc(sizeof(ElemType)*MAXSIZE);
    //存储分配失败退出
    if (!L->data) return ERROR;
    //空表长度为0
    L->length = 0;
    return OK;
}

  • 注意:需要注意的是:
  1. 数组的长度是存放线性表的存储空间的长度。
  2. 线性表的长度是线性表中数据元素的个数,随着线性表的增删改查,线性表的长度是有变化的。
  3. 在任意时刻,线性表的长度该小于等于数组的长度。
顺序表插入

初始条件:顺序线性表L已存在,1≤i≤ListLength(L);
操作结果:``中第i个位置之前插入新的数据元素e,L的长度加1

注意index下标从0开始,i1开始 ,i开始i-1哪个下标之后

思路:
1.插入位置不合理,抛出异常。例如数组的长度为20,线性表的长度为10,插入的位置是15,显然不合规矩的,顺序线性链表中的元素是连续的。
2.如果未向线性表中插入数据之前,线性表的长度等于数组长度(不可能大于),则抛出异常或动态增加容量。
3.从第i个位置遍历到最后一个元素,将这些元素都向后移动一个位置。
4.将要插入的元素放置到位置i处。
5.线性表长length加一。
时间复杂度 O(n)

Status ListInset(Sqlist *L,int i,ElemType e){
   ////线性表已填满
    if (L->length > SIZE_MAX) return ERROR;
    //length == 100 i==101,102就是越界
    ////插入位置不合理,抛出异常。
    if(i<1 || (i > L->length +1)) return ERROR;
  
    
     //插入数据不在表尾,则先移动出空余位置
    //i <= L->length  从最后一个移动
    if (i<=L->length){
       // L->length 是下标加一 , L->length-1刚好最后一位下标
        for(int j=L->length-1;j>=i-1;j--){
            //插入位置以及之后的位置后移动1位
            L->data[j+1] = L->data[j];
        }
    }
    //将新元素e 放入第i个位置上
    L->data[i-1] = e;
    //长度+1;
    ++L->length;
    return OK;
    
}
顺序表的取值

思路:
1.线性表不能为空。
2.下标不能小于1。
3.下标i不能大于线性表长。

时间复杂度:O(1)

Status GetElem(Sqlist L,int i,ElemType *e){
    //判断i值是否合理, 若不合理,返回ERROR
    if (i<1 || i>L.length) return ERROR;
    //data[i-1]单元u存储第i个数据元素
    *e = L.data[i-1];
    return OK;
}
顺序表删除

思路:
1.如果删除位置不合理,抛出异常。例如数组的长度为20,线性表的长度为10,删除的位置是15,显然不合规矩的,顺序线性链表中的元素是连续的。
2.取出删除的元素。
3.从删除元素的位置开始遍历到最后一个元素结束,分别将他们都向前移动1个位置。
4.线性表长length减一。
时间复杂度 O(n)

Status DeleElem(Sqlist *L,int i,ElemType *e){
    if (L->length == 0) return ERROR;
    if (i<1 || (i>L->length+1)) return ERROR;
     // 删除第i个元素,
    for(int j=i;j<L->length;j++){
             //被删除元素之后的元素向前移动
            L->data[j-1] = L->data[j];
    }
    
    //表长度-1;
    --L->length;
    
    return OK;
}
清空顺序表

初始条件:顺序线性表L已存在。操作结果:将L重置为空表

Status ClearList(Sqlist *L){
    L->length = 0;
    return OK;
}
判断顺序表清空
Status ListEmpty(Sqlist L){
    if(L.length == 0){
        return TRUE;
    }
    return FALSE;
}
获取顺序表长度ListEmpty元素个数 */
Status ListLength(Sqlist L){
    return L.length;
}
顺序输出List

初始条件:顺序线性表L已存在
操作结果:依次对L的每个数据元素输出

Status TraverseList(Sqlist L){
  
    for(int i=0;i<L.length;i++){
        printf("%c\n",L.data[I]);
    }
    printf("\n");
    return OK;
}
顺序表查找元素并返回位置

初始条件:顺序线性表L已存在
操作结果:返回L中第1个与e满足关系的数据元素的位序。
若这样的数据元素不存在,则返回值为0

int LocateElem(Sqlist L,ElemType e){
    int I;
    if (L.length == 0) return ERROR;
    for (i=0; i<L.length; i++) {
        if (L.data[i] == e){
            break;
        }
    }
    if (i>=L.length) return 0;
    return I+1;
}
顺序表 元素是否在线性顺序表中

元素是否在线性顺序表中
@param list 线性顺序存储表
@param elem 元素
@return ERROR 不存在;SUCCESS 存在

Status ElemisExitInList(Sqlist L,ElemType e){
   
   if (L.length == 0) return ERROR;
   for (int i=0; i<L.length; i++) {
       if (L.data[i] == e){
           return OK;
       }
   }
   return ERROR;
}
两个线性表的合并 没有重复的元素。

假设Lb向L合并,这里面涉及一个扩容问题

memcpy(data, L->data, sizeof(ElemType) * 2 * MAXSIZE);

Status combineTwoLinkLists(Sqlist *L,Sqlist L1){
   
    int LLength = L->length;
    int L1Length = L1.length;
    if (LLength + L1Length > LLength){
        ElemType* data = malloc(sizeof(ElemType) * 2 * MAXSIZE);
        //从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
        memcpy(data, L->data, sizeof(ElemType) * 2 * MAXSIZE);
        free(L->data);
        L->data = data;
        if(!L->data) exit(ERROR);
    }
    
    for (int i=0; i<L1Length; i++) {
        ElemType e = L1.data[I];
        Status isState = ElemisExitInList(*L, e);
        if (isState == ERROR){
            ListInsert(L, LLength-1, e);
        }
    }
    
    TraverseList(*L);
    return OK;
}

最后插入数据时候 可以将MAXSIZE*2 看看是否全部打印

image.png
  • 示例
 Sqlist L;
    ElemType e;
    Status isStatus;
    //1.1 顺序表初始化
    isStatus = InitList(&L);
    printf("初始化L后: L.Length = %d\n", L.length);
    //1.2 顺序表插入数据
    char a[6] = {'a','b','c','d','e','\0'};
    char *b = a;
    for (int i=1; i<=5; i++) {
        isStatus = ListInset(&L,i , *(b+i-1));
    }
     printf("插入数据L长度: %d\n",L.length);
   //1.3 顺序表取值
    GetElem(L, 2, &e);
    printf("顺序表L第%d个元素的值为:%c\n",2,e);
   //1.4 顺序表删除元素
    DeleElem(&L, 2, &e);
    printf("顺序表删除第%d元素%c,长度为%d\n",2,e,L.length);
    TraverseList(L);
    //1.5 清空顺序表
    isStatus = ClearList(&L);
     TraverseList(L);
    // 判断list是否为空
    isStatus = ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",isStatus);
    for (int i=1; i<=5; i++) {
           isStatus = ListInset(&L,i , *(a+i-1));
    }
    TraverseList(L);
  • 打印
初始化L后: L.Length = 0
插入数据L长度: 5
顺序表L第2个元素的值为:b
顺序表删除第2元素b,长度为4
a
c
d
e


L是否空:i=1(1:是 0:否)
a
b
c
d
e

线性表创建已经存在,内存空间已经分配,只要lengtn=0,就不会访问.

总结

  • 优点:取出元素很容易。不用为表示表中元素之间的逻辑关系而增加额外的存储空间。

  • 缺点:删除和插入要移动大量元素。删除的时候容易造成存储空间碎片。线性表的长度变化较大时,难以控制存储空间的容量.线性表的数组长度需要给定。

单链表

在顺序结构中,每个数据元素只需要存储数据元素的信息就可以了。在链式存储过程中,除了要存储数据元素的信息外,还要存储它的后继元素的存储地址。把存储数据元素信息的区域称为数据域,把存储直接后继位置成为指针域。指针域中存储的信息称为指针或者链。指针域和数据域两部分信息组成数据元素的存储映像,称为结点。

定义:单链表:n个结点链组成一个链表,即为线性表的链式存储结构。因为此结点中只包含一个指针域,所以叫单链表

  • 结点 数据不联系,数据之间通过指针域联系.
  • 第一个结点首元结点,最有一个指针域为NULL
  • 单链表后面的元素找不到前面的.

链表中的第一个结点的存储位置称为头指针。最后一个结点的指针为空。
单链表的第一个结点前附设一个结点,称为头结点

image.png
image.png
image.png
  • 头结点和头指针的区分

头指针是指向链表中第一个结点的指针。头结点是为了操作的统一方便设立的,放在第一个元素的结点之前。若链表中有头结点,那么链表中的第一个结点就是头结点了,所以头指针此刻指向的是头结点的指针

头指针具有标识作用,所以常用头指针冠以链表的名字。无论链表是否为空,头指针均不为空。头指针是链表的必要元素。

疑问:为什么空链表一定要有头指针,个人认为链表为空表示链表存在,但是没有任何结点。头指针此刻更觉得像是存储着空链表的地址。

链表有了头结点,在对第一元素结点前插入结点和删除第一个结点,其操作与其他结点的操作就统一了。头结点不一定是链表的必需元素。

  • 开始行动,做一个单链表
宏定义 ,数据结构
typedef struct Node* LinkList; // 声明一个struct Node*类型的变量

设计链表可以在首元结点前面加一个头结点,首指针指向头结点,方便删除添加,作为一个标记.便于操作首元结点.

image.png
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OK 1

#define MAXSIZE 20 /* 存储空间初始分配量 */
typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */

//定义节点
typedef struct Node{
    ElemType data;
    struct Node *next;//下一个节点 
}Node;

typedef struct Node* LinkList; //
初始化单链表线性表

结e点是初始化带入的


Status InitList(LinkList *L){
    
    //产生头结点,并使用L指向此头结点
    *L = (LinkList)malloc(sizeof(Node));
    //存储空间分配失败
    if(*L == NULL) return ERROR;
    //将头结点的指针域置空
    (*L)->next = NULL;
    
    return OK;
}
单链表插入

初始条件:顺序线性表L已存在,1≤i≤ListLength(L);
操作结果:在L中第i个位置之后插入新的数据元素e,L的长度加1;

  • LinkList *L L保存的是LinkList地址,(*L)拿到是LinkList*,然后才是指向结构体的指针
  • LinkList L 是指向结构体的指针
image.png

假设i=4


image.png

如果找到插入节点上一个结点,因为每次 p = p->next,查找i-1次,所以要从头结点开始.

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

   int j;
   LinkList p,s;
   p = *L;
   j = 1;
   
   //寻找第i-1个结点
  
   while (p && j<i) {
       //j=4
       p = p->next;
       ++j;
   }
   
   //第i个元素不存在
   if(!p || j>i) return ERROR;
   
   //生成新结点s
   s = (LinkList)malloc(sizeof(Node));
   //将e赋值给s的数值域
   s->data = e;
   //将p的后继结点赋值给s的后继
   s->next = p->next;
   //将s赋值给p的后继
   p->next = s;
   
   return OK;
}
单链表取值

初始条件: 顺序线性表L已存在,1≤i≤ListLength(L);
操作结果:用e返回L中第i个数据元素的值

  • 头结点的next内元素一次往下遍历
Status GetElem(LinkList L,int i,ElemType *e){
   
   //j: 计数.
   int j;
   //声明结点p;
   LinkList p;
   
   //将结点p 指向链表L的第一个结点;
   p = L->next;
   //j计算=1;
   j = 1;
   
   
   //p不为空,且计算j不等于i,则循环继续
   while (p && j<i) {
       
       //p指向下一个结点
       p = p->next;
       ++j;
   }
   
   //如果p为空或者j>i,则返回error
   if(!p || j > i) return ERROR;
   
   //e = p所指的结点的data
   *e = p->data;
   return OK;
   
   
}
单链表删除元素

初始条件:顺序线性表L已存在,1≤i≤ListLength(L)
操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1

从首元节点开始遍历,所以遍历次次数是j<(i-1),
p = p->next;相当于提前走一次找到4的前一个3位置就要在第2次停止

Status ListDelete(LinkList *L,int i,ElemType *e){
    
    int j;
    LinkList p,q;
    p = (*L)->next;
    j = 1;
    
    //查找第i-1个结点,p指向该结点
    while (p->next && j<(i-1)) {
        p = p->next;
        ++j;
    }
    
    //当i>n 或者 i<1 时,删除位置不合理
    if (!(p->next) || (j>i-1)) return  ERROR;
    
    //q指向要删除的结点
    q = p->next;
    //将q的后继赋值给p的后继
    p->next = q->next; // cc->cooci
    //将q结点中的数据给e
    *e = q->data; //删除的值
    //让系统回收此结点,释放内存;
    free(q); //释放q
    
    return OK;
}
遍历显示

初始条件:顺序线性表L已存在
操作结果:依次对L的每个数据元素输出

Status ListTraverse(LinkList L)
{
    LinkList p=L->next;
    while(p)
    {
        printf("%d\n",p->data);
        p=p->next;
    }
    printf("\n");
    return OK;
}
置空链表

初始条件:顺序线性表L已存在。操作结果:将L重置为空表

Status ClearList(LinkList *L)
{
    LinkList p,q;
    p=(*L)->next;           /*  p指向第一个结点 */
    while(p)                /*  没到表尾 */
    {
        q=p->next;
        free(p);
        p=q;
    }
    (*L)->next=NULL;        /* 头结点指针域为空 */
    return OK;
}
单链表前插入法

随机产生n个元素值,建立带表头结点的单链线性表L(前插法)


image.png

每次循环 都让头结点next指向新创建的结点
新创建的结点的next指向 头结点的next

void CreateListHead(LinkList *L, int n){
    
    LinkList p;
    
    //建立1个带头结点的单链表
    *L = (LinkList)malloc(sizeof(Node));
    (*L)->next = NULL;
    
    //循环前插入随机数据
    for(int i = 0; i < n;i++)
    {
        //生成新结点
        p = (LinkList)malloc(sizeof(Node));
       
        //i赋值给新结点的data
        p->data = I;
        //p->next = 头结点的L->next,头结点的下一个节点
        p->next = (*L)->next;
        
        //(*L)->next有两个指向他,修改一下 让头结点不指向他
        
        //将结点P插入到头结点之后,头结点指向新建的节点
        (*L)->next = p;
        
    }
}
单链表后插入法
image.png

随机产生n个元素值,建立带表头结点的单链线性表L(后插法)

发现后面的数据在最前面
生成头结点,并且给r,目的保存尾节点
创建一个节点,r指向她,并保存为尾节点,最后将rnext置空.

void CreateListTail(LinkList *L, int n){
    
    LinkList p,r;
 
    //建立1个带头结点的单链表
    *L = (LinkList)malloc(sizeof(Node));
    //r指向尾部的结点
    r = *L;
    
    for (int i=0; i<n; i++) {
        
        //生成新结点
        p = (Node *)malloc(sizeof(Node));
        p->data = I;
        
        //将表尾终端结点的指针指向新结点
        r->next = p;
        //将当前的新结点定义为表尾终端结点 r指向尾结点 
        r = p; // r指向p,
        
    }
    
    //将尾指针的next = null
     r->next = NULL;
    
}
实例
Status iStatus;
        LinkList L;
        ElemType e;
   
        //2.1 单链表初始化
        iStatus = InitList(&L);
        printf("L 是否初始化成功?(0:失败,1:成功) %d\n",iStatus);
        
        //2.2 单链表插入数据
        for(int j = 1;j<=5;j++)
        {
            iStatus = ListInsert(&L, 1, j);
        }
        printf("L 插入后\n");
        ListTraverse(L);
        
        //2.3 单链表获取元素
        GetElem(L,5,&e);
        printf("第5个元素的值为:%d\n",e);
        
        //2.4 删除第5个元素
        iStatus = ListDelete(&L, 5, &e);
        printf("删除第5个元素值为:%d\n",e);
        ListTraverse(L);
        
        //3.1 前插法整理创建链表L
        iStatus = ClearList(&L);
        CreateListHead(&L, 5);
        printf("整理创建L的元素(前插法):\n");
        ListTraverse(L);
        
        //3.2 后插法整理创建链表L
        iStatus = ClearList(&L);
        CreateListTail(&L, 5);
        printf("整理创建L的元素(后插法):\n");
        ListTraverse(L);
打印
 是否初始化成功?(0:失败,1:成功) 1
L 插入后
5
4
3
2
1

第5个元素的值为:1
删除第5个元素值为:1
5
4
3
2

整理创建L的元素(前插法):
4
3
2
1
0

整理创建L的元素(后插法):
0
1
2
3
4

Program ended with exit code: 0
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • 线性表:零个或多个数据元素的有限序列。 线性表元素的个数n(n>=0)定义为线性表的长度,当n=0时,称为空表。 ...
    开心糖果的夏天阅读 263评论 0 2
  • 线性表的学习 学习目标 线性表的定义 线性表的存储方式和表达方式 基本实现 基本操作实现 双向链表插入和删除实现 ...
    JiaJianHuang阅读 257评论 0 0
  • 满足数据元素不同,但是在同一个线性表中的元素必定具有相同的特点,即属于同一数据对象, 相邻数据元素之间存在这个序偶...
    yan0_0阅读 151评论 0 1
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,485评论 16 22
  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,551评论 0 11