数据结构知识学习小结

一、动态内存分配基本步骤

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;
}

下面这张就是十字存储结构的基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值