您的位置:首页 > 理论基础 > 数据结构算法

数据结构笔记二

2015-06-03 19:06 435 查看
预习:
结构和指针:

计算机存储和处理数据基本上都放在内存中,如何管理呢??
用变量对应一块内存。

变量-----代表 一块内存

int i = 1;
int j = 5;

i,j分别对应一块内存

变量类型----决定内存的大小。

int i = 1;//4个字节
char c = 'c'; //1个字节

变量类型--简单类型和复合类型
简单类型:int char float double
复合类型:结构、联合和枚举

布尔类型--C89没有布尔类型,但在c99加入了_Bool类型(强加的类型)

结构是什么?

多个数据放在一起,构成了结构。结构其实就是一片连续的内存,可以存放任意数量的任意类型的数据。

一般来说,多个不同类型的相关数据放在一起的办法就是结构。

struct Emp{//员工的数据封在结构中
int num;//员工编号
char name[20];//员工的姓名
};

struct Emp 作为一个类型出现,这个类型包括所有的成员。在C语言中,此类型为struct Emp,sturct不能省。

struct Emp emp 其实就是结构对应的一块内存,在这块内存中,成员从上到下依次排列。(有对齐和补齐的字节数:注意)

结构的地址需要&取一下。
指针、数组、字符串不需要&。

取结构的成员有两种常见的方式:

(1)(结构的使用)
struct Emp emp;
emp.num = 1;

(2)(结构指针的使用)
struct Emp* pe = malloc(sizeof(struct Emp));
pe->num = 1;

1 #include <stdio.h>
2
3 struct Emp{
4 int id;//4
5 char name[18];//18?20>
6 int age;//4
7 };
8
9 int main()
10 {
11 struct Emp emp;
12 printf("size=%d\n",sizeof(emp));//28,age有对齐
13 printf("emp=%p\n",emp);//-1代表错误地址 warning.
14 printf("emp=%p\n",&emp);//正确
15 printf("emp.id=%p\n",&emp.id);//结构的地址与第一个元素的地址相同的
16 printf("emp.name=%p\n",emp.name);//字符串不需要加&取地址
17 printf("emp.age=%p\n",&emp.age);
18 return 0;
19 }

指针:
int fa(){
int y = 200;
return y;
}
int main()
{
int x = 100;//希望x能够把fa()结果返回
x = fa();
}

一般来说,变量名 代表的是 一块内存,但在使用时,变量名 是无法直接获取的。

变量等于内存中的数据。而想获取变量对应的内存地址需要用&,这种变量地址的类型就是指针。

int x = 1;
x就相当于1
int * pi = &x;
pi就是x的地址,而不是1.
pi也是一个变量,也对应一块内存。

pi 代表的是x的地址,如果想取x的数据,用*pi,就是1.
pi和&x都是x的地址;
*pi和x都是x的数据;

1 #include <stdio.h>
2 #include <stdlib.h>
3 void fa(int x,int *pi){
4 printf("x=%d\n",x);//x = 100
5 printf("pi=%p,*pi=%d\n",pi,*pi);//pi = 地址, *pi 100
6 x = 200;
7 *pi = 200;
8
9 }
10 int main()
11 {
12 int a = 100;
13 int b = 100;
14 int * pb = &b;
15 printf("pb =%p\n",pb);
16 fa(a,pb);
17 printf("a=%d,b=%d\n",a,b);//a =100; b =200
18 return 0;
19 }

数据结构之队列Queue:----应用非常广泛(OS里面的消息队列;网络编程 )

队列的特点:

先进(压入push)先出(弹出pop),后进后出。

void fa(){
int a;
if (a>5){
int b;
}//b出栈
}//a出栈
----先进后出

int main(){
int c;
fa();
fb();
}
变量定义的顺序:c,a,b 出栈顺序b,a,c

----每一个函数都有一个函数栈

所有函数都是使用栈存储数据的(函数栈),只要数据需要排队的都是需要队列。

队列包括一个队首和一个队尾,放入元素在队尾的后面并以新元素为新的队尾,
取出的元素就是队首并把下一个元素作为新的队首。

基于顺序表(数组)的队列 下标要循环利用,到最大值以后就要回到0,放入时找队尾下标,取出找队首下标

(圆)数组有5个元素,下标为0-4;
一开始没有数据时,队首和队尾下标都是0开始;
没有人出队时,队首的下标就是0;
放入第1个元素10时,队首下标不变0,队尾下标后移至1;
放入第2个元素20时,队首元素10下标不变0,第2个元素为20下标为1,队尾下标后移至2;
放入第3个元素30时,30下标为2队尾下标为3
放入第4个元素40时,40下标为3队尾下标为4
放入第5个元素50时,50下标为4队尾下标为0了----数组满了。队列满了。

当队首和队尾重合在一起时,如果不是空的就是满的。

移除元素第一个元素时,10出队,队首下标指向1了,队尾下标不变。
进入一个元素60时,60进队,队首下标指向1了,队尾下标也指向1了。---数组和队列又满了

数组实现队列的时候一定要考虑 下标回零 的问题。

struct Queue{
int * arr;//数组的首地址
size_t cap;//数组的长度 容量
size_t front;//队首前端、对手下标
size_t rear;//队列后端、队尾下标
size_t size;//队列中元素的个数,为了区分front和rear所处位置相同时
};

运算结构:
创建和销毁
入队和出队
判空和判满
查看元素个数
查看队首不能查看队尾
qa.h
1 #ifndef _QA_H
2 #define _QA_H
3 #include <sys/types.h>
4 typedef struct Queue{
5 int * arr;//数组的首地址
6 size_t cap;//数组的容量,数组的长度
7 size_t front;//队首下标
8 size_t rear;//队尾下标
9 size_t size;//真实存在的元素的数量
10 }QUEUE;
11 //初始化队列函数
12 void queue_init(QUEUE* queue,size_t cap);
13 //回收队列函数
14 void queue_deinit(QUEUE* queue);
15 //判断队满
16 int queue_full(QUEUE* queue);
17 //判断队空
18 int queue_empty(QUEUE* queue);
19 //入队函数
20 void queue_push(QUEUE* queue,int data);
21 //出队函数
22 int queue_pop(QUEUE* queue);
23 //查看队首函数
24 int queue_front(QUEUE* queue);
25 //查看队列大小函数
26 size_t queue_size(QUEUE* queue);
27 #endif

qa.c
1 #include <stdlib.h>
2 #include "qa.h"
3 //初始化队列函数
4 void queue_init(QUEUE* queue,size_t cap){
5 queue->arr = malloc(sizeof(int)*cap);
6 queue->cap = cap;
7 queue->front = 0;
8 queue->rear = 0;
9 queue->size = 0;
10 }
11 //回收队列函数
12 void queue_deinit(QUEUE* queue){
13 free(queue->arr);
14 queue->arr = NULL;
15 queue->cap = 0;
16 queue->front = 0;
17 queue->rear = 0;
18 queue->size = 0;
19 }
20 //判断队满
21 int queue_full(QUEUE* queue){
22 return queue->size >= queue->cap;
23 }
24 //判断队空
25 int queue_empty(QUEUE* queue){
26 return !queue->size;
27 }
28 //入队函数
29 void queue_push(QUEUE* queue,int data)
30 {//判断队尾下标是否到达最大值,如果是最大值了就回0;还要判断是否满;---在这里没判断满,在应用时要判断满。
31 if (queue->rear >= queue->cap) queue->rear = 0;//下标增加
32 queue->arr[queue->rear] = data;//数据放队尾
33 queue->rear++;//队尾后移
34 queue->size++;//元素数量加
35 }
36 //出队函数
37 int queue_pop(QUEUE* queue){
38 if (queue->front >= queue->cap) queue->front = 0;
39 queue->size--;//元素的数量减少
40 //int temp = queue-> arr[queue->front];
41 //queue->size--;//元素的数量减少
42 //return temp;
43 return queue->arr[queue->front++];
44 }
45 //查看队首函数
46 int queue_front(QUEUE* queue){
47 if (queue->front >= queue->cap) queue->front = 0;
48 return queue->arr[queue->front];
49 }
50 //查看队列大小函数
51 size_t queue_size(QUEUE* queue){
52 return queue->size;
53 }
54

-------------------------------------------------------------------------
测试用例1:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "qa.h"
4 int main()
5 {
6 QUEUE queue;
7 queue_init(&queue,5);
8 int i;
9 if (!queue_full(&queue)){
10 for (i=0;i<5;i++)
11 {
12 queue_push(&queue,i);
13 }
14 }
15 printf("size=%d\n",queue_size(&queue));
16 if (!queue_empty(&queue)){
17 for (i=0;i<5;i++)
18 {
19 printf("%d\n",queue_pop(&queue));
20 }
21 }
22 printf("size=%d\n",queue_size(&queue));
23 queue_deinit(&queue);
24
25 return 0;
26 }
~

--------------------------------------------------------------------
测试用例2:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "qa.h"
4 int main(){
5 QUEUE queue;
6 queue_init(&queue,5);
7 int i;
8 for (i=0;i<20;i++){
9 if (queue_full(&queue))
10 {
11 printf("size=%d\n",queue_size(&queue));
12 printf("pop %d\n",queue_pop(&queue));
13 printf("size=%d\n",queue_size(&queue));
14 }
15 else
16 {
17 printf("size=%d\n",queue_size(&queue));
18 queue_push(&queue,i);
19 printf("insert %d\n",i);
20 printf("size=%d\n",queue_size(&queue));
21 }
22 }
23 printf("size=%d\n",queue_size(&queue));
24 if (!queue_empty(&queue)){
25 for (i=0;i<5;i++){
26 printf("%d\n",queue_pop(&queue));
27 }
28 }
29 printf("size=%d\n",queue_size(&queue));
30 queue_deinit(&queue);
31 return 0;
32 }

----------------------------------------------------------------------
测试用例3:
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include "qa.h"
4
5 int main()
6 {
7
8 QUEUE queue;//创建队列
9
10 queue_init(&queue,5);
11
12 int i;
13 for(i=0;i<5;i++){
14 if (!queue_full(&queue))//如果队列不满就加
15 {
16 queue_push(&queue,i);
17 }
18 }
19
20 printf("size = %d\n",queue_size(&queue));
21 //queue.front = 0;
22 while(!queue_empty(&queue)){
23
24 printf("%d\n",queue_pop(&queue));
25
26 }
27 queue_deinit(&queue);
28 }

-------------------------------------------------------------------------

基于链表式的队列 没有满,只有判断空。

动态分配、前后指针、注意判空

链表式的队列 需要两个结构:节点 和 队列

struct QueueNode{
int data; //数据
struct QueueNode * next;//下一个节点的地址
};

struct Queue{
struct QueueNode* front;//队首节点
struct QueueNode* rear;//队尾节点
};

放入队列 找 队尾节点,弹出队列找队首节点。

空队列没有节点: 队首指针和队尾指针都是空的,节点是空的;

一开始队列front和rear都是NULL。
放入第一个元素时,front和rear都指向第一个元素,再放入时,front不变,改变的是rear的指向和原来的rear的next。
(放入第二个元素时,front的指针不变,队尾的指针要变;)(队尾的next总是为null。)

出队时,改变front,指向next并释放节点内存,但删除最后一个时,rear也要改成NULL。

----------------------------------------------------------------------------
ql.h

1 #ifndef _QL_H
2 #define _QL_H
3 #include <sys/types.h>
4 typedef struct QueueNode{//链式表的节点
5 int data;//数据
6 struct QueueNode * next;//下一个元素的地址
7 }QUEUE_NODE;
8 typedef struct Queue{//队列
9 QUEUE_NODE *front;//队首节点地址 负责出队
10 QUEUE_NODE *rear;//队尾节点地址 负责入队
11 }QUEUE;
12 void queue_init(QUEUE* queue);//初始化为空
13 void queue_deinit(QUEUE* queue);//释放节点后删除
14 int queue_empty(QUEUE* queue);//判断是否为空
15 void queue_push(QUEUE* queue,int data);//入队
16 int queue_pop(QUEUE* queue);//出队
17 int queue_front(QUEUE* queue);//队首查看
18 size_t queue_size(QUEUE* queue);//取元素数量
19 #endif

--------------------------------------------------------------------------
ql.c

1 #include <stdlib.h>
2 #include "ql.h"
3 static QUEUE_NODE* create_node(int data){
4 QUEUE_NODE* node = malloc(sizeof(QUEUE_NODE));
5 node->data = data;
6 node->next = NULL;//队列的新节点next必须为NULL,都是加在队尾的
7 return node;
8 }
9 static QUEUE_NODE* destroy_node(QUEUE_NODE * node){
10 QUEUE_NODE * next = node->next;//node->next当前队首节点指向的下一个节点,将会变成新的队首。
11 free(node);//释放当前节点
12 return next; //返回新的队首的地址
13 }
14 void queue_init(QUEUE * queue){//初始化为空
15 queue->front = NULL;
16 queue->rear = NULL;
17 }
18 void queue_deinit(QUEUE * queue){//释放节点后删除
19 while(queue->front)
20 queue->front = destroy_node(queue->front);
21 queue->rear = NULL;
22
23 }
24 int queue_empty(QUEUE* queue){//判断是否为空
25 return (!queue->front) && (!queue->rear);
26
27 }
28 void queue_push(QUEUE* queue,int data){//入队(需要深刻理解)
29 QUEUE_NODE* node = create_node(data)
30 if (queue->rear)//不是第一个
31 queue->rear->next = node;//改的是原先的队尾的next
32 else//是第一个
33 queue->front = node;
34 queue->rear = node;
35 }
36 int queue_pop(QUEUE* queue){//出队
37 int data = queue->front->data;
38 queue->front = destroy_node(queue->front);
39 if (!queue->front) queue->rear = NULL;
40 return data;
41 }
42 int queue_front(QUEUE* queue){//队首查看
43 return queue->front->data;
44
45 }
46 size_t queue_size(QUEUE* queue){//取元素数量
47 size_t size = 0;
48 QUEUE_NODE* node;
49 for (node = queue->front;node;node=node->next)
50 {
51 size++;
52 }
53 return size;
54 }

--------------------------------------------------------------
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include "ql.h"
4
5 int main()
6 {
7
8 QUEUE queue;//创建队列
9
10 queue_init(&queue);
11
12 int i;
13
14 for(i=0;i<5;i++){
15
16 queue_push(&queue,i);
17 }
18
19 printf("size = %d\n",queue_size(&queue));
20
21 //queue.front = 0;
22 while(!queue_empty(&queue)){
23
24 printf("%d\n",queue_pop(&queue));
25
26 }
27
28 queue_deinit(&queue);
29 }

--------------------------------------------------------------

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: