一、动态内存分配基本步骤
1、内存分配简单示例:
个人对于示例的理解:
定义一个整型的指针变量p(着重认为它是一个“变量”我觉得可能会更好理解),这个变量用来存地址的,而不是“值”,malloc函数参数给空间字节数,图中就是四个字节32位,这个函数返回值是那片数据类型的一个指针,你用强制转换(int*)之后,那片数据类型的一个指针就是整数类型。15赋值给变量*p,打印变量值,释放内存,将地址p传过去。
可以看到p指向了那片空间的地址,*p变量存在101地址,它的值是15,根据地址,15被指向了那片空间的地址(500),这样值就存在了500地址那里。
实际测试也可以发现,变量*p的值是16,p地址被存在一个地方,但是其指向那一片开辟出来的空间的地址,那一片地址就放着变量的值,所以第二行地址跟第四行的地址是一样的。
2、结构体的内存分配
首先理解一下结构体。typedef :给数据类型换个别名。,本身结构体应该是
typedef struct 结构体名字
{
}
别名;
这样来定义的,不过都有别名了,为了简便,可以省去结构体名字。
然后第二个知识点,malloc分配了多少个字节?换成char x;int y;呢?答案都是八个字节,因为c语言有补位原理要遵循(附讲解)。
第三个、p->元素,是c语言为了简便的又一种写法,跟(*p).元素是一样的(附有实际测试图)。
第四、类比上面那个示例,这里就是malloc开辟了一片8个字节的空间,数据类型是po这个结构体类型,地址则被赋值给p,由p指向这片空间(附实际测试图)。可以看到,其实就是指向第一个元素的地址。然后8到C刚好是12-8=4个字节,说明char x的大小也补成了4个字节。
二、绪论(概念性的,无聊)
1、
程序 = 算法 + 数据结构;算法的五个重要特性:有穷性,确定性,可行性,输入,输出。
2、f(n)是什么
3、常量阶
f(n)计算出来是常量,那都是O(1),不管常量有多大,算法的时间复杂度都是O(1)。
4、线性阶
5、平方阶
后面的例题我感觉都挺难的,应该不会出。我们有个阶的概念就行。重点是理解上面的动态内存分配。
三、线性表(顺序表和链式表)
1、一些基本概念
2、顺序表
几点说明:将int重命名为ElemType很有必要,方便以后统一修改数据类型。
以后的函数我感觉习惯上都要有返回值,来验证有没有正确执行。
只是单纯定义了一个变量list,而不是*list指针变量,但是函数都是要接收指针,所以传参的时候都是取地址&。
下面几个函数就是比较常用的了。能默写出来才说明有最基本的了解。
#include <stdio.h>
#include "stdlib.h"
#include "string.h"
#define MAXSIZE 100
typedef int ElemType;
typedef struct
{
ElemType data[MAXSIZE];
int length;
}Seglist;
void initlist(Seglist* L)//初始化顺序表长度
{
L->length = 0;
}
int listElem(Seglist* L)//遍历元素
{
int i = 0;
for (i = 0; i < L->length; i++)
{
printf("%d ", L->data[i]);
}
printf("\n");
return 1;
}
int InsertElem(Seglist* L, int pos, ElemType e)//合理范围内,在顺序表中插入一个元素并且保持递增排序
{
if (pos<1 || pos>L->length)
{
printf("插入位置错位\n");
return 0;
}
if (pos <= L->length)
{
int i = 0;
for (i = L->length - 1; i >= pos - 1; i--)
{
L->data[i + 1] = L->data[i];
}
L->data[pos - 1] = e;
L->length++;
//排序部分
int k = 0, j = 0;
for (k = 0; k < L->length; k++)
{
for (j = 0; j < L->length - k - 1; j++)
{
if (L->data[j] > L->data[j + 1])
{
ElemType temp = L->data[j];
L->data[j] = L->data[j + 1];
L->data[j + 1] = temp;
}
}
}
return 1;
}
}
int appendElem(Seglist* L, ElemType e)//在尾部添加一个元素
{
if (L->length >= MAXSIZE)
{
printf("顺序表满了!\n");
return 0;
}
L->data[L->length] = e;
L->length++;
return 1;
}
int main(void)
{
Seglist list;
initlist(&list);
printf("初始化成功,目前使用长度为%d\n", list.length);
printf("目前占用内存:%d\n", sizeof(list.data));
appendElem(&list, 10);
appendElem(&list, 20);
appendElem(&list, 30);
appendElem(&list, 50);
listElem(&list);
InsertElem(&list, 2, 40);
listElem(&list);
return 0;
}
3、链(式)表
单链表
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
typedef int Elemtype;
typedef struct node
{
Elemtype data;
struct node* next;
}Node;
Node* intiList()
{
Node* head = (Node*)malloc(sizeof(Node));
head->data = 0;
head->next = NULL;
return head;
}
int Inserthead(Node* L,Elemtype e)
{
Node* p = (Node*)malloc(sizeof(Node));
p->data = e;
p->next = L->next;
L->next = p;
return 1;
}
void listNode(Node* L)
{
Node* p = L->next;
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int listLength(Node* L)
{
Node* p = L;
int len = 0;
while (p != NULL)
{
p = p->next;
len++;
}
return len;
}
Node* deleteDuplicates(Node* L)//每个元素只出现一次
{
Node* prev = L;//存储有效节点前驱?
Node* current = L->next;//存储当前节点
Elemtype hashtable[500] = { 0 };//哈希表,统计0-500之间的数字是否出现
while (current != NULL)
{
if (hashtable[current->data] == 1)//说明是重复值,要跳过这个值同时释放内存空间
{
prev->next = current->next;//先把要删除的节点的后继链接上来删除节点的前驱
free(current);
current = prev->next;
}
else
{
hashtable[current->data] = 1;
prev = current;
current = current->next;
}
}
return L;
}
Node* deletex_y(Node* L,Elemtype x,Elemtype y)//删除x到y之间的元素返回处理之后的链表
{
Node* prev = L;//存储有效节点前驱?
Node* current = L->next;//存储当前节点
while (current != NULL)
{
if (current->data >= x && current->data <= y)//说明是重复值,要跳过这个值同时释放内存空间
{
prev->next = current->next;//先把要删除的节点的后继链接上来删除节点的前驱
free(current);
current = prev->next;
}
else
{
prev = current;
current = current->next;
}
}
return L;
}
Node* mergeDescending(Node* A, Node* B)//合并同时排序
{
Node* C = intiList();
Node* p = A->next;
Node* q = B->next;
while (q != NULL && p != NULL)
{
if (p->data <= q->data)
{
Inserthead(C, p->data);
p = p->next;
}
else
{
Inserthead(C, q->data);
q = q->next;
}
}
while (q != NULL)
{
Inserthead(C, q->data);
q = q->next;
}
while (p != NULL)
{
Inserthead(C, p->data);
p = p->next;
}
return C;
}
int main(void)
{
Node* list = intiList();
Inserthead(list, 15);
Inserthead(list, 20);
Inserthead(list, 30);
Inserthead(list, 40);
listNode(list);
printf("链表节点数:%d\n", listLength(list));
Inserthead(list, 20);
listNode(list);
//deleteDuplicates(list);
//listNode(list);
deletex_y(list, 20, 30);
listNode(list);
Node* A = intiList();
Inserthead(A, 8);Inserthead(A, 6);
Inserthead(A, 4);Inserthead(A, 2);
listNode(A);
Node* B = intiList();
Inserthead(B, 7); Inserthead(B, 5);
Inserthead(B, 3); Inserthead(B, 1);
listNode(B);
Node* C = mergeDescending(A, B);
listNode(C);
return 1;
}
双向链表
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef int Elemytpe;
typedef struct node
{
Elemytpe data;
struct node* prev, * next;
}Node;
int Inserthead(Node* L, Elemytpe e)
{
Node* p = (Node*)malloc(sizeof(Node));
p->data = e;
p->prev = L;//新指向1
p->next = L->next;//新指向2
if (L->next != NULL)//2不为空
{
L->next->prev = p;//2指向新
}
L->next = p;//1指向新
return 1;
}
Node* get_tail(Node* L)
{
Node* p = L;
while (p->next != NULL)
{
p = p->next;
}
return p;
}
Node* Inserttail(Node* tail, Elemytpe e)
{
Node* p = (Node*)malloc(sizeof(Node));
p->data = e;
p->prev = tail;
tail->next = p;
p->next = NULL;
return p;
}
void listElem(Node* L)
{
Node* p = L->next;
while(p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int InserNode(Node* L, int pos, Elemytpe e)
{
Node* p = L;
int i = 0;
while (i < pos - 1)
{
p = p->next;
i++;
if (p == NULL)
{
printf("插入位置错误!\n");
return 0;
}
}
Node* q = (Node*)malloc(sizeof(Node));
q->data = e;
q->prev = p;
q->next = p->next;
p->next->prev = q;
p->next = q;
return 1;
}
int DeleteNode(Node* L, int pos, Elemytpe e)
{
Node* p = L;
int i = 0;
while (i < pos - 1)
{
p = p->next;
if (p == NULL)
{
printf("删除节点的位置错误!\n");
return 0;
}
}
Node* q = (Node*)malloc(sizeof(Node));
}
int main(void)
{
Node* list = (Node*)malloc(sizeof(Node));
list->next = NULL;
list->prev = NULL;
Inserthead(list, 20);
Inserthead(list, 20);
Node* tail = get_tail(list);
tail = Inserttail(tail, 15);
tail = Inserttail(tail, 14);
listElem(list);
InserNode(list, 2, 11);
listElem(list);
return 0;
}
四、栈和队列
五、树
以下概念都要知道,是理解树的重要基础。
下面是递归法遍历二叉树的几种简单实际代码。
#include "stdio.h"
#include "stdlib.h"
typedef char ElemType;
typedef struct TreeNode
{
ElemType data;
struct TreeNode* lchild;
struct TreeNode* rchild;//需要struct
}TreeNode;
typedef TreeNode* BiTree;//定义指针为BiTree
char str[] = "ABDH#K###E##CFI###G#J##";
int index = 0;
void CreatTree(BiTree* T) {
ElemType ch;
ch = str[index++];
if (ch == '#')
*T = NULL;
else {
*T = (BiTree)malloc(sizeof(TreeNode));//
(*T)->data = ch;
CreatTree(&(*T)->lchild);//现在叠加了一层指针,(*T)参数是一个BiTree类型的的变量,
//参数要传入指针或者地址
CreatTree(&(*T)->rchild);
}
}
void preOrder(BiTree T) {
if (T == NULL)
return;
printf("%c ", T->data);
preOrder(T->lchild);
preOrder(T->rchild);
}
void Inorder(BiTree T){
if (T == NULL)
return;
Inorder(T->lchild);
printf("%c ", T->data);
Inorder(T->rchild);
}
void Postorder(BiTree T) {
if (T == NULL)
return;
Postorder(T->lchild);
Postorder(T->rchild);
printf("%c ", T->data);
}
int main(void){
BiTree T;
CreatTree(&T);
preOrder(T);
printf("\n");
Inorder(T);
printf("\n");
Postorder(T);
printf("\n");
return 1;
}
下面这张就是十字存储结构的基础。