数据结构(持续更新...)

字符串

取消scanf保护输入

项目——xxx属性——c/c++——预处理器——预处理定义下箭头——编辑

添加 _CRT_SECURE_NO_WARNINGS

字符数组和字符串

char date[] = "june 14";
char *date = "june 14";
  1. 两种声明都可以作为字符串。尤其是,任何期望传递字符数组或字符指针的函数都能够接收这两种声明的date作为参数

  2. 区别:1.声明为数组时,可以任意修改储存在date中的字符。声明为指针时,date指向字符串字面量,不可修 改

    2.声明为数组时,date时数组名,声明为指针时,date为变量,可以指向其他字符串;

读写字符串

区分空白字符,空字符,空格符,制表符

  1. 空白字符:空白字符(whitespace)指的是任意dao多个基本空白字符(包括空格、制表符\t、回车换行符\n)的连续组合。

  2. 空字符(注意,不叫空白字符)是指'\0',或者是字符的编码值为0的字符

1.输出字符串

char str = "Are we having funny yet";
printf("%s",str);
put(str)//自动换行

2.读入字符串

scanf("%s",str);//读入字符后,只输入第一个空白字符之前的字符串
get(str);//在换行符处停止

字符串库函数

  1. strcpy

char *strcpy(char *s1,char *s2);//将s2复制给s1
  1. strlen

char *strlen(const char *s);//返回s长度
  1. strcat

char *strcat(char *s1,const char *s2);//拼接s1,s2
int main() {
char *a;
gets(a);//使用未初始化变量a
printf("%s", a);
}

宏定义

#define LISTINCREMENT 100//注意没有分号

例题

/*利用牛顿迭代法计算方程3x³-2x²-5=0在1附近的根,要求精确到1e-5,牛顿迭代公式x=x-f(x)/f'(x)。*/
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
float a = 1e-5;
float x = 1;
float x0 = x - (3 * x * x * x - 2 * x * x - 5) / (9 * x * x - 4 * x);
while (fabs(x-x0)>=a) {
x0 = x;
x = x - (3 * x * x * x - 2 * x * x - 5) / (9 * x * x - 4 * x);
}
printf("%lf", x);
}

 

dijkstra

//dijkstra
/*
数据
6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
结果:0 1 8 4 13 17*/
#include<stdio.h>
#define inf 0x7f
int main() {
int dis[20], e[20][20], b[20] = { 0 };
int m, n, min, u=0;
scanf_s("%d%d", &m,&n);//m个点,n条边 忘记点和边的区分
/*for (int i = 1; i <= m; i++) {//错误2
e[i][i] = 0;
for (int j = 1; j <= m; j++) {
e[i][j] = inf;
}
}*/
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= m; j++) {
if (i == j) e[i][j] = 0;
else e[i][j] = inf;
}
}
for (int i = 1; i <= n; i++) {
int p, q, r;
scanf_s("%d%d%d", &p, &q, &r);
e[p][q] = r;
}
for (int i = 1; i <= n; i++) {//错误点1:忘记初始化dis[]
dis[i] = e[1][i];
}
for (int i = 1; i <= m; i++) {//m写成n
   min = inf;//int min =inf
for (int j = 1; j <= m; j++) {
//int min = inf;时间复杂度高
//dis[i] = e[1][i];错误1:初始化位置错误
if (dis[j] < min&& b[j]==0) {//小错误:j,写成i
min = dis[j];
u = j;//记录第一个最短点
}
}
b[u] = 1;
/*for (int j = 1; j <= n; j++) {
if (e[1][j] < inf) {
if (e[1][j] > e[1][u] + dis[u]) {
e[1][j] = e[1][u] + dis[u];
}
}
}*/
for (int j = 1; j <= m; j++) {
if (e[u][j] < inf) {
if (dis[j] > dis[u] + e[u][j] && b[j] == 0) {
dis[j] = dis[u] + e[u][j];
}
}
}
}
for (int i = 1; i <= m; i++) {
printf("%d ", dis[i]);
}
}
/*步骤解析:
1.初始化边e[i][j]
2.输入数据
3.初始化dis[]
4.寻找最短边
5.用最短边更新其它边
*/
//查找长度为n的数组a的第一个等于key的元素;
int search2(const int* a, int n, int key) {
int l = 0, r = n - 1, mid = 0, ans = 0;
while (l <= r) {
mid = (l + r) / 2;
if (a[mid] < key)
l = mid + 1;
else {//关键看等号
ans = mid;
r = mid - 1;
}
}
return a[ans] == key ? ans : -1;
}

//查找长度为n的数组a中的最后一个等于key得元素;
int search1(const int* a, int n, int key) {
int l = 0, r = n - 1, mid = 0, ans = 0;
while (l <= r) {
mid = (l + r) / 2;
if (a[mid] <= key) {//关键看等号在哪里
l = mid + 1;
ans = mid;//只有在取等的地方才能取值
}
else
r = mid - 1;
}
return a[ans] == key ? ans : -1;
}

二级指针

  1. 如果我们要在一个函数内改变一个指针的值,我们就需要将形参定义了二级指针

  2. 新的理解:在为某个结构体写初始化函数时,主函数声明的是结构体指针变量(注意,使用函数包装结构体初始化代码),使用二级指针,在别的函数内malloc的函数只在函数返回之前有效。

  3. #include<stdlib.h>
    #include<stdio.h>
    typedef struct LinkNode1 {
    int number;
    int que;
    LinkNode1* next;
    }LinkNode;

    void Insert(LinkNode** L, int num, int q) {//让L始终指向链尾
    //不使用二级指针无法改变L指向
    LinkNode* r = (LinkNode*)malloc(sizeof(LinkNode));
    r->number = num;
    r->que = q;
    r->next = (*L)->next;
    (*L)->next = r;
    (*L) = (*L)->next;//未成功改变L
    }
    //int slove(LinkNode* L, int m) {
    //for(int i=1;i<m;i++)
    //}
    int main() {
    int m, n;
    LinkNode *L=NULL;
    scanf("%d", &m);
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
    int number;
    scanf("%d", &number);
    if(i==1){
    LinkNode* p = (LinkNode*)malloc(sizeof(LinkNode));
    p->number = number;
    p->que = i;
    L = p;
    p->next = p;
    }
    else{
    Insert(&L, number, i);
    }

    }
    L = L->next;//让L回到起始点
    for (int i = 1; i <= n; i++) {
    printf("%d ", L->number);
    printf("%d ", L->que);
    printf("\n");
    L = L->next;
    }
    }
  4.  

链表

//二级指针改变本身初始化为空的指针
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct Node {
ElemType data;
struct Node* next;
}LinkNode, * LinkList;
//
void Link(LinkNode **L,int n) {//尾插法
LinkNode* q = NULL;
for (int i = 0; i < n; i++) {
LinkNode* p = (LinkNode*)malloc(sizeof(LinkNode));
ElemType data;
scanf_s("%d", &data);
p->data = data;
q = p;
p->next = (*L);
(*L) = q;
}
return;
}
void Link1(LinkNode **L,int n) {//头插法
LinkNode* p = (LinkNode*)malloc(sizeof(LinkNode));
ElemType i;
scanf_s("%d", &i);
p->data = i;
p->next = NULL;
(*L) = p;
LinkNode* r=p;
for (int i = 0; i < n-1; i++) {
LinkNode* q = (LinkNode*)malloc(sizeof(LinkNode));
ElemType data;
scanf_s("%d", &data);
q->data = data;
q->next = NULL;
r->next = q;
r = q;
}
}
int main() {
LinkNode *head=NULL;
int n;
scanf_s("%d ", &n);
Link1(&head, n);
while(head){
printf("%d ", head->data);
head = head->next;
       //head = head.next;不能将LinkNode*型赋给LinkNode型
}

}
  1. 链表的遍历:

    1. if(p) if(p!=NULL)的区别

使用野指针

0xcccccccc : Used by Microsoft's C++ debugging runtime library to mark uninitialised stack memory

* 0xcdcdcdcd : Used by Microsoft's C++ debugging runtime library to mark uninitialised heap memory

* 0xfeeefeee : Used by Microsoft's HeapFree() to mark freed heap memory

* 0xabababab : Used by Microsoft's HeapAlloc() to mark "no man's land" guard bytes after allocated heap memory

* 0xabadcafe : A startup to this value to initialize all free memory to catch errant pointers

* 0xbaadf00d : Used by Microsoft's LocalAlloc(LMEM_FIXED) to mark uninitialised allocated heap memory

* 0xbadcab1e : Error Code returned to the Microsoft eVC debugger when connection is severed to the debugger

* 0xbeefcace : Used by Microsoft .NET as a magic number in resource files

平时我们只需要了解上面常见的三种就可以了:0xcccccccc、0xcdcdcdcd和 0xfeeefeee ,以帮我们迅速地发现问题并分析问题。

对于0xcccccccc和0xcdcdcdcd,在 Debug 模式下,VC 会把未初始化的栈内存上的指针全部填成 0xcccccccc ,当字符串看就是 “烫烫烫烫……”;会把未初始化的堆内存上的指针全部填成 0xcdcdcdcd,当字符串看就是 “屯屯屯屯……”。那么调试器为什么要这么做呢?VC的DEBUG版会把未初始化的指针自动初始化为0xcccccccc或0xcdcdcdcd,而不是就让取随机值,那是为了方便我们调试程序,如果野指针的初值不确定,那么每次调试同一个程序就可能出现不一样的结果,比如这次程序崩掉,下次却能正常运行,这样显然对我们解bug是非常不利的,所以自动初始化的目的是为了让我们一眼就能确定我们使用了未初始化的野指针了。

对于0xfeeefeee,是用来标记堆上已经释放掉的内存。注意,如果指针指向的内存被释放了,变量变量本身的地址如未做改动,还是之前指向的内存的地址。如果该指针是一个类的指针,并且类中包含有指针变量,则内存被释放后(对于C++类,通常是执行delete操作),类中的指针变量就会被赋值为0xfeeefeee。如果早调试代码过程中,发现有值为0xfeeefeee的指针,就说明对应的内存被释放掉了,我们的代码已经出问题了。

关于VC 中 debug和Release模式下的变量初始化问题

摘自https://blog.csdn.net/chenlycly/article/details/23708049

遍历的表表尾必须指向NULL

#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct LinkNode1 {
   ElemType data;
   struct LinkNode1* next;
}LinkNode, LinkList;
void Insert(LinkNode* L, ElemType e) {
   LinkNode* p = (LinkNode*)malloc(sizeof(LinkNode));
   p->data = e;
   LinkNode* q = L;
   q->next = p;
   q = q->next;
}
void G(LinkNode* L1, LinkNode* L2) {
   LinkNode* p = L1;
   LinkNode* q = L2;
   LinkNode* r = L1->next;
   LinkNode* s = L2->next;
   while (r && s) {
       if (r->data > s->data) {
           s->next = r;
           p->next = s;
           q = q->next;
           s = s->next;
      }
       else if (r->data < s->data) {
           p = p->next;
           r = r->next;
      }
       else {
           q = q->next;
           p = p->next;
           r = r->next;
           s = s->next;
      }
  }
   if (!r) {
       r->next = s;
  }
}
int main() {
   LinkNode* a = (LinkNode*)malloc(sizeof(LinkNode));
   LinkNode* b = (LinkNode*)malloc(sizeof(LinkNode));

   int n, data;
   LinkNode* q;
   for (int i = 0; i < 2; i++) {
       scanf("%d", &n);
       if (i == 0) {
           q = a;
      }
       else {
           q = b;
      }
       for (int j = 0; j < n; j++) {
           scanf("%d", &data);
           LinkNode* p = (LinkNode*)malloc(sizeof(LinkNode));
           p->data = data;
           p->next = NULL;//无此句无法遍历
           q->next = p;
           q = q->next;
      }
  }
   while (a->next) {
       printf("%d ", a->next->data);
       a = a->next;
  }
   while (b) {
       printf("%d ", b->next->data);
       b = b->next;
  }
}

在某个函数中malloc的空间在函数结束被销毁

#include<stdlib.h>
#include<stdio.h>
#define Size 10
typedef struct SqList {
   float* x;//系数
   float* y;//指数
   int size;
}Sq;
void Init(Sq* L1) {
   int n;
   scanf("%d", &n);
   L1->x = (float*)malloc(sizeof(float) * n);
   L1->y = (float*)malloc(sizeof(float) * n);
   L1->size = n;
   float a, b;
   for (int i = 0; i < n; i++) {
       scanf("%f%f", &a, &b);
       L1->x[i] = a;
       L1->y[i] = b;
  }
}
void Add(Sq* L1, Sq* L2) {
   int m = 0, n = 0;
   Sq L3;
   int i = 0;
   L3.size = L1->size + L2->size;
   L3.x = (float*)malloc(sizeof(float) * (L1->size + L2->size));
   L3.y = (float*)malloc(sizeof(float) * (L1->size + L2->size));
   while (m < L1->size && n < L2->size) {
       if (L1->y[m] < L2->y[n]) {
           L3.x[i] = L1->x[m];
           L3.y[i] = L1->y[m];
           i++;
           m++;
         
      }
       else if (L1->y[m] > L2->y[n]) {
           L3.x[i] = L2->x[n];
           L3.y[i] = L2->y[n];
           i++;
           n++;
 
      }
       else {
           L3.x[i] = L1->x[m] + L2->x[n];
           L3.y[i] = L1->y[m] + L2->y[n];
           if (L3.x[i] == 0) {
               m++;
               n++;
               L3.size = L3.size - 2;
          }
           else {
               i++;
               m++;
               n++;
               L3.size--;
          }

      }
  }
   if (m >= L1->size) {
       while (n < L2->size) {
           L3.x[i] = L2->x[n];
           L3.y[i] = L2->y[n];
           i++;
           n++;
      }
  }
   else if(n>=L2->size){
       while (m < L1->size) {
           L3.x[i] = L1->x[m];
           L3.y[i] = L1->y[m];
           i++;
           m++;
      }
  }
   if (L3.size == 0) {
       printf("0");
  }
   else {
       for (int i = 0; i < L3.size; i++) {
           printf("%g ", L3.x[i]);
           printf("%g ", L3.y[i]);
      }
  }
}
int main() {
   Sq L1, L2;
   Init(&L1);
   Init(&L2);
   Add(&L1, &L2);
   //无法在主函数中输出,因为L3malloc的空间被销毁了,L3->x[i]与L3->y[i]不在存在
}

  1. 声明某个结构体后,如果以此结构体声明某个结构体变量,该变量自动声明有所有成员变量的空间,而如果声明的是结构体指针变量,则需要自己malloc空间并赋值

  2. 关于函数中malloc空间被销毁的问题,栈中却没有消失,因为是malloc的是结构体成员变量

  3. 主函数声明结构体指针并且没有赋值,需要用某个函数进行初始化时,因为该指针为NULL,所以初始化函数需要使用二级指针,如果主函数声明的是结构体变量,则不需要用二级指针

队列

  1. 循环队:

    1. 循环队的入队出队:入队在队尾,出队在队首

    2. 循环队入队出队操作:当使用顺序循环队时,入队必须模加,出队也用模加

    3. 顺序循环队判空判满:也使用模加;

  2. 循环队列的特点体现在入队和出队中

  3.  

posted @ 2020-11-10 15:51  Deair  阅读(64)  评论(0编辑  收藏  举报