数据结构总结

什么是数据结构

数据结构是用来处理数据和数据之间的逻辑关系,实现需要的功能的操作

1.数据结构主要研究数据之间的特定关系:

  1. 逻辑关系
  2. 存储关系
  3. 操作(数据运算):增删改查

2.1 逻辑关系

  1. 逻辑关系主要是指数据之间在逻辑上的关系,与存储位置无关,主要是指邻接关系,从属关系。

1)线性关系

  1. 一对一的关系,任何一个数据最多只能有一个直接前驱和一个直接后继。
  2. 例如:排队买东西。对应的数据结构:线性表,栈,队列

2)树形关系

  1. 一对多的关系,任何一个数据只能有一个直接前驱,但是可以有多个后继。
  2. 例如:族谱,公司组织架构图。对应数据结构:树,二叉树

3)图形关系

  1. 多对多的关系
  2. 例如:地铁图

2.2 存储关系

数据在内存中是如何存储的,实际位置的关系

1)顺序存储

  1. 数据在内存中会开辟一块连续的空间进行存储。一般使用数组来存储数据。(物理位置是相邻的)

2)链式存储

  1. 数据在内存中不需要开辟连续的空间存储。(物理位置不相邻)

本文重点

本文主要是用于自己复习,所以会对自己不清楚的地方进行一个梳理。

1、单链表

cs 复制代码
//单链表
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
//结点的创建
struct list
{
	char name[20];
	int age;//数据域
	int id;
	struct list *next;//指针域
};
//单链表的创建--头结点创建
struct list * list_creat()
{
	struct list *P=(struct list *)malloc(sizeof(struct list));
	if(P==NULL)
	{
		printf("创建头结点失败\n");
		return NULL;
	}
	memset(P->name,0,sizeof(P->name));
	P->age=0;
	P->id=0;
	P->next=NULL;
	return P;
}
//数据插入------头插法
bool list_head_insert(struct list *P,char name[],int age,int id )
{
	if(P==NULL)
	{
		struct list*node=(struct list *)malloc(sizeof(struct list));
		if(node==NULL)
		{
			printf("结点创建失败\n");
			return false;
		}
		node=P->next;//如果没有节点,则创建一个节点,地址的指向更改指向新节点
		strcpy(node->name,name);
		node->age=age;
		node->id=id;
		node->next=NULL;
		return true;
	}
	else
	{
		struct list *node=(struct list *)malloc(sizeof(struct list));
		if(node==NULL)
		{
			printf("结点创建失败\n");
			return false;
		}
		struct list *temp=P->next;
		strcpy(node->name,name);
		node->age=age;
		node->id=id;
		node->next=temp;
		P->next=node;
		return true;
	}
}
//尾插法
bool list_tail_insert(struct list *P,char name[],int age,int id)
{
	if(P==NULL)
	{
		struct list *node=(struct list *)malloc(sizeof(struct list));
		if(node==NULL)
		{
			printf("结点创建失败\n");
			return false;
		}
		strcpy(node->name,name);
		node->age=age;
		node->id=id;
		P->next=node;
		node->next=NULL;
		return true;
	}
	else
	{
		int num;
		struct list *node=(struct list*)malloc(sizeof(struct list));
		if(node==NULL)
		{
			printf("结点创建失败\n");
			return false;
		}
		while(P->next!=NULL)
		{
			P=P->next;
		}
		struct list *temp=P;
		strcpy(node->name,name);
		node->age=age;
		node->id=id;
		temp->next=node;
		node->next=NULL;
		return true;
	}
}
//指定位置插入
bool list_len_insert(struct list *P,char name[],int age,int id,int len)
{
	int i=0;
	struct list *head=P;//防止头指针变更,创建新指针来代替头指针
	while(head->next!=NULL)
	{
		head=head->next;
		i++;
	}
	if(len<1 || i<len)
	{
		printf("输入长度错误\n");
		return false;
	}
	else
	{
		struct list *node=(struct list*)malloc(sizeof(struct list));
		strcpy(node->name,name);
		node->age=age;
		node->id=id;
		node->next=NULL;
		int k=0;
		struct list *temp=P;
		while(temp->next!=NULL)
		{
			k++;
			if(k==len)
			{
				struct list *Pin=temp->next;
				temp->next=node;
				node->next=Pin;
				break;
			}
			temp=temp->next;
		}
		return true;
	}
}
//头部删除
bool list_head_del(struct list*P)
{
	if(P==NULL)
	{
		printf("链表为空,删除失败\n");
		return false;
	}
	struct list *temp=P;
	struct list *node=P->next;
	temp->next=node->next;
	node->next=NULL;
	free(node);
	return true;
}
//尾部删除
bool list_tail_del(struct list *P)
{
	if(P==NULL)
	{
		printf("链表为空,删除失败\n");
		return false;
	}
	struct list *temp=P;
	struct list *P_tail=P->next;
	while(P_tail->next!=NULL)
	{
		temp=temp->next;
		P_tail=P_tail->next;
	}
	temp->next=NULL;
	//P_tail->next=NULL;
	free(P_tail);
	return true;
}
//指定位置删除
bool list_len_del(struct list *P,int len)
{
	if(P==NULL)
	{
		printf("链表为空,删除失败\n");
		return false;
	}
	int k=0;
	struct list * node=P;
	while(node->next!=NULL)
	{
		k++;
		node=node->next;
	}
	if(len<1 || len>k)
	{
		printf("输入长度错误\n");
		return false;
	}
	int num=0;
	struct list *P_first=P;
	struct list *P_two=P->next;
	while(P_two->next!=NULL)
	{
		num++;
		if(num==len)
		{
			struct list *P_node=P_two->next;
			P_first->next=P_node;
			P_two->next=NULL;
			free(P_two);
			return true;
		}
		P_first=P_first->next;
		P_two=P_two->next;

	}
	return false;
}
//编历链表
bool list_erg(struct list *P)
{
	if(P==NULL)
	{
		printf("链表为空,遍历失败\n");
		return false;
	}
	while(P->next!=NULL)
	{
		P=P->next;
		printf("name=%s,age=%d,id=%d\n",P->name,P->age,P->id);
		
	}
	return true;
}
int main(int argc, const char *argv[])
{
    //输入数据进链表------头插法输入
	struct list*P=list_creat();
	list_head_insert(P,"zhangsan",20,1);
	list_head_insert(P,"lisi",21,2);
	list_head_insert(P,"wangwu",22,3);
	list_head_insert(P,"liuer",24,4);
	list_erg(P);//遍历链表
	printf("``````````````````````````、n\n");
	list_tail_insert(P,"E",29,9);//尾插法输入
	list_tail_insert(P,"D",28,8);
	list_tail_insert(P,"C",27,7);
	list_tail_insert(P,"B",26,6);
	list_tail_insert(P,"A",25,5);
	list_erg(P);
	printf("```````````````````````\n");
	list_len_insert(P,"lp",21,10,3);//指定位置输入
	list_erg(P);
	printf("`````````````````````\n");
	//删除头部
	list_head_del(P);
	list_erg(P);//
	//删除尾部	
	printf("`````````````````````\n");
	list_tail_del(P);
	list_erg(P);
	//指定位置删除
	printf("`````````````````````\n");
	list_len_del(P,2);
	list_erg(P);
	return 0;
}

输出如下

cs 复制代码
name=liuer,age=24,id=4
name=wangwu,age=22,id=3
name=lisi,age=21,id=2
name=zhangsan,age=20,id=1
``````````````````````````、n
name=liuer,age=24,id=4
name=wangwu,age=22,id=3
name=lisi,age=21,id=2
name=zhangsan,age=20,id=1
name=E,age=29,id=9
name=D,age=28,id=8
name=C,age=27,id=7
name=B,age=26,id=6
name=A,age=25,id=5
```````````````````````
name=liuer,age=24,id=4
name=wangwu,age=22,id=3
name=lp,age=21,id=10
name=lisi,age=21,id=2
name=zhangsan,age=20,id=1
name=E,age=29,id=9
name=D,age=28,id=8
name=C,age=27,id=7
name=B,age=26,id=6
name=A,age=25,id=5
`````````````````````
name=wangwu,age=22,id=3
name=lp,age=21,id=10
name=lisi,age=21,id=2
name=zhangsan,age=20,id=1
name=E,age=29,id=9
name=D,age=28,id=8
name=C,age=27,id=7
name=B,age=26,id=6
name=A,age=25,id=5
`````````````````````
name=wangwu,age=22,id=3
name=lp,age=21,id=10
name=lisi,age=21,id=2
name=zhangsan,age=20,id=1
name=E,age=29,id=9
name=D,age=28,id=8
name=C,age=27,id=7
name=B,age=26,id=6
`````````````````````
name=wangwu,age=22,id=3
name=lisi,age=21,id=2
name=zhangsan,age=20,id=1
name=E,age=29,id=9
name=D,age=28,id=8
name=C,age=27,id=7
name=B,age=26,id=6

以上就只是单链表的操作,包括数据的插入(头插法,尾插法,指定位置插入),删除(头部删除,尾部删除,指定位置删除)

2、循环单链表

cs 复制代码
//循环单链表
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
//结点的创建
struct list
{
	char name[20];
	int age;//数据域
	int id;
	struct list *next;//指针域
};
//循环单链表的创建--头结点创建
struct list * list_creat()
{
	struct list *P=(struct list *)malloc(sizeof(struct list));
	if(P==NULL)
	{
		printf("创建头结点失败\n");
		return NULL;
	}
	memset(P->name,0,sizeof(P->name));
	P->age=0;
	P->id=0;
	P->next=P;
	return P;
}
//数据插入------头插法
bool list_head_insert(struct list *P,char name[],int age,int id )
{
	if(P->next==P)
	{
		//struct list *Pin=P;
		struct list*node=(struct list *)malloc(sizeof(struct list));
		if(node==NULL)
		{
			printf("结点创建失败\n");
			return false;
		}
		//对新建结点初始化
		memset(node->name,0,sizeof(node->name));
		node->age=0;
		node->id=0;
		node->next=NULL;
		//对新建结点赋值
		strcpy(node->name,name);
		node->age=age;
		node->id=id;
		//连接头结点和新建结点
		P->next=node;
		node->next=P;
		return true;
	}
	else
	{
		struct list *node=(struct list *)malloc(sizeof(struct list));
		if(node==NULL)
		{
			printf("结点创建失败\n");
			return false;
		}
		memset(node->name,0,sizeof(node->name));
		node->age=0;
		node->id=0;
		node->next=NULL;
		struct list *temp=P->next;
		strcpy(node->name,name);
		node->age=age;
		node->id=id;
		P->next=node;
		node->next=temp;
		return true;
	}
}
//尾插法
bool list_tail_insert(struct list *P,char name[],int age,int id)
{
	if(P->next==P)
	{
		struct list *node=(struct list *)malloc(sizeof(struct list));
		if(node==NULL)
		{
			printf("结点创建失败\n");
			return false;
		}
		node->next=NULL;
		strcpy(node->name,name);
		node->age=age;
		node->id=id;
		P->next=node;
		node->next=P;
		return true;
	}
	else
	{
		struct list *node=(struct list*)malloc(sizeof(struct list));
		if(node==NULL)
		{
			printf("结点创建失败\n");
			return false;
		}
		memset(node->name,0,sizeof(node->name));
		node->age=0;
		node->id=0;
		node->next=NULL;
		struct list *Pin=P;//定义新指针,避免直接操作头指针
		while(Pin->next!=P)
		{
			Pin=Pin->next;
		}
		struct list *temp=Pin;
		strcpy(node->name,name);
		node->age=age;
		node->id=id;
		temp->next=node;
		node->next=P;//最后一个结点指向头结点
		return true;
	}
}
//指定位置插入
bool list_len_insert(struct list *P,char name[],int age,int id,int len)
{
	int i=0;
	struct list *head=P;//防止头指针变更,创建新指针来代替头指针
	while(head->next!=P)
	{
		head=head->next;
		i++;
	}
	if(len<1 || i<len)
	{
		printf("输入长度错误\n");
		return false;
	}
else
	{
		struct list *node=(struct list*)malloc(sizeof(struct list));
		strcpy(node->name,name);
		node->age=age;
		node->id=id;
		node->next=NULL;
		int k=0;
		struct list *temp=P;
		while(temp->next!=P)
		{
			k++;
			if(k==len)
			{
				struct list *Pin=temp->next;
				temp->next=node;
				node->next=Pin;
				break;
			}
			temp=temp->next;//从头结点的下一个结点开始遍历
		}
		return true;
	}
}
//头部删除
bool list_head_del(struct list*P)
{
	if(P->next==P)
	{
		printf("链表为空,删除失败\n");
		return false;
	}
	struct list *temp=P;
	struct list *node=P->next;
	temp->next=node->next;
	node->next=NULL;
	free(node);
	return true;
}
//尾部删除
bool list_tail_del(struct list *P)
{
	if(P->next==P)
	{
		printf("链表为空,删除失败\n");
		return false;
	}
	struct list *temp=P;
	struct list *P_tail=P->next;
	while(P_tail->next!=P)
	{
		temp=temp->next;
		P_tail=P_tail->next;
	}
	temp->next=P;//让倒数第二个结点指向头结点
	P_tail->next=NULL;//最后一个结点指向空指针,防止野指针
	free(P_tail);
	return true;
}
//指定位置删除
bool list_len_del(struct list *P,int len)
{
	if(P->next==P)
	{
		printf("链表为空,删除失败\n");
		return false;
	}
	int k=0;
	struct list * node=P;
	while(node->next!=P)
	{
		k++;
		node=node->next;
	}
	if(len<1 || len>k)
	{
		printf("输入长度错误\n");
		return false;
	}
	int num=0;
	struct list *P_first=P;
	struct list *P_two=P->next;
	while(P_two->next!=P)
	{
		num++;
		if(num==len)
		{
			struct list *P_node=P_two->next;
			P_first->next=P_node;//让要删除的上一个结点指针指向要删除的下一个结点,即把要删除的指针拿出来
			P_two->next=NULL;//让要删除的指针指向空指针,防止野指针
			free(P_two);
			return true;
		}
		P_first=P_first->next;
		P_two=P_two->next;

	}
	return false;
}
//编历链表
bool list_erg(struct list *P)
{
	if(P->next==P)
	{
		printf("链表为空,遍历失败\n");
		return false;
	}
	struct list *temp=P;
	while(temp->next!=P)
	{
		temp=temp->next;
		printf("name=%s,age=%d,id=%d \n",temp->name,temp->age,temp->id);
	}
	return true;
}
int main(int argc, const char *argv[])
{
	//输入数据到循环单链表中------头插法
	struct list*P=list_creat();
	list_head_insert(P,"zhangsan",20,1);
	list_head_insert(P,"lisi",21,2);
	list_head_insert(P,"wangwu",22,3);
	list_head_insert(P,"liuer",24,4);
	list_erg(P);
	printf("``````````````````````````、n\n");
	//输入数据到循环单链表中------尾插法
	list_tail_insert(P,"E",29,9);
	list_tail_insert(P,"D",28,8);
	list_tail_insert(P,"C",27,7);
	list_tail_insert(P,"B",26,6);
	list_tail_insert(P,"A",25,5);
	list_erg(P);
	printf("```````````````````````\n");
	//输入数据到循环单链表中------指定位置插入
	list_len_insert(P,"lp",21,10,3);
	list_erg(P);
	printf("`````````````````````\n");
	//删除头部
	list_head_del(P);
	list_erg(P);//
	//删除尾部	
	printf("`````````````````````\n");
	list_tail_del(P);
	list_erg(P);
	//指定位置删除
	printf("`````````````````````\n");
	list_len_del(P,2);
	list_erg(P);
	return 0;
}

输出

cs 复制代码
//头插法插入数据
name=liuer,age=24,id=4 
name=wangwu,age=22,id=3 
name=lisi,age=21,id=2 
name=zhangsan,age=20,id=1 
``````````````````````````、n
//尾插法插入数据
name=liuer,age=24,id=4 
name=wangwu,age=22,id=3 
name=lisi,age=21,id=2 
name=zhangsan,age=20,id=1 
name=E,age=29,id=9 
name=D,age=28,id=8 
name=C,age=27,id=7 
name=B,age=26,id=6 
name=A,age=25,id=5 
```````````````````````
//指定位置插入输入
name=liuer,age=24,id=4 
name=wangwu,age=22,id=3 
name=lp,age=21,id=10 
name=lisi,age=21,id=2 
name=zhangsan,age=20,id=1 
name=E,age=29,id=9 
name=D,age=28,id=8 
name=C,age=27,id=7 
name=B,age=26,id=6 
name=A,age=25,id=5 
`````````````````````
//头部删除法
name=wangwu,age=22,id=3 
name=lp,age=21,id=10 
name=lisi,age=21,id=2 
name=zhangsan,age=20,id=1 
name=E,age=29,id=9 
name=D,age=28,id=8 
name=C,age=27,id=7 
name=B,age=26,id=6 
name=A,age=25,id=5 
`````````````````````
//尾部删除法
name=wangwu,age=22,id=3 
name=lp,age=21,id=10 
name=lisi,age=21,id=2 
name=zhangsan,age=20,id=1 
name=E,age=29,id=9 
name=D,age=28,id=8 
name=C,age=27,id=7 
name=B,age=26,id=6 
`````````````````````
//指定位置删除法
name=wangwu,age=22,id=3 
name=lisi,age=21,id=2 
name=zhangsan,age=20,id=1 
name=E,age=29,id=9 
name=D,age=28,id=8 
name=C,age=27,id=7 
name=B,age=26,id=6 

3、双向链表和循环双向链表

需要读者自己去自己操作,这里我感觉浪费时间,直接进入栈和队列

4、栈

1、这里的栈不是我们说的堆区和栈区的栈,而是逻辑结构上像弹夹一样固定一端的顺序表,但是再存储方式上分为顺序栈和链栈,数据遵守先进后出原则。

1、顺序栈

  1. 用顺序表实现的栈。
  2. 所以栈的创建,入栈出栈的代码与操作顺序表一致,只不过要求只能在一端进行操作。
  3. 笔试题较多的是:要求写出满栈,空栈的条件。看清楚题目,pos是从0开始还是从-1开始。
cs 复制代码
//顺序栈
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#define MAX 10
struct stack
{
	int buf[MAX];
	int top;//栈顶指针,但不是指针,指向栈顶元素
};
//创建栈
struct stack *stack_creat()
{
	struct stack *P=(struct stack*)malloc(sizeof(struct stack));
	if(P==NULL)
	{
		printf("创建失败\n");
		return NULL;
	}
	//创建栈之后要进行数据初始化
	memset(P->buf,0,sizeof(P->buf));
	P->top=-1;
	return P;
}
//栈是否为空
bool stack_empty(struct stack*P)
{
	if(P->top==-1)
	{
		return true;
	}
	return false;
}
//栈是否为满
bool stack_full(struct stack *P)
{
	if(P->top==MAX-1)
	{
		return true;
	}
	return false;
}
//入栈
bool stack_insert(struct stack*P,int value)
{
	if(stack_full(P))
	{
		printf("栈已满,入栈失败\n");
		return false;
	}
	P->top++;
	P->buf[P->top]=value;
	return true;
}
//出栈
bool stack_out(struct stack*P,int *value)//用一个地址来存储出栈的数据
{
	if(stack_empty(P))
	{
		printf("栈为空,出栈失败\n");
		return false;
	}
	*value=P->buf[P->top];
	P->buf[P->top]=0;//出栈之后,对元素赋值为空
	P->top--;//将栈顶指针后移
	return true;
}
//访问栈顶元素
bool stack_top(struct stack *P,int *value)
{
	if(stack_empty(P))
	{
		printf("栈为空,访问失败\n");
		return false;
	}
	*value=P->buf[P->top];
	return true;
}
//计算栈的长度
int stack_len(struct stack *P)
{
	if(stack_empty(P))
	{
		printf("栈为空\n");
		return 0;
	}
	int len=0;
	int num=0;
	int value;
	while(P->top!=-1)
	{
		stack_out(P,&value);
		len++;
	}
	return len;
}
int main(int argc, const char *argv[])
{
	int value,len,top;
	struct stack *P=stack_creat();
	stack_insert(P,12);
	stack_insert(P,13);
	stack_insert(P,14);
	stack_insert(P,15);
	stack_out(P,&value);
	stack_top(P,&top);
	len=stack_len(P);
	printf("len=%d,value=%d,top=%d\n",len,value,top);

	return 0;
}

2.链栈

cs 复制代码
#include "stdio.h"
#include "stdlib.h"
#include "stdbool.h"
struct Node
{
	int data;
	struct Node *next;
	int top;
};
//另外一种方式
/*
 struct Top
 {
 	struct Node *top;
 };
 */
//创建空栈
struct Node *Stack_Create()
{
	struct Node *L=(struct Node *)malloc(sizeof(struct Node));
	if(L==NULL)
	{
		printf("链栈创建失败!\r\n");
		return NULL;
	}
	L->data=0;
	L->next=NULL;
	L->top=-1;
	return L;
}
//栈判空
bool is_empty(struct Node *L)
{
	if(L->top==-1)
	{
		return true;
	}
	return false;
}
//入栈:尾插法,栈只能再一端操作,如果使用尾插法插入,那么出战也只能在尾部出
bool push(struct Node *L,int data)
{
	if(L->next==NULL)
	{
		struct Node *node=(struct Node *)malloc(sizeof(struct Node));
		if(node==NULL)
		{
			return false;
		}
		node->data=data;
		node->next=NULL;
		L->next=node;
		L->top++;//栈顶指针加1
		return true;
	}
	struct Node *node=(struct Node *)malloc(sizeof(struct Node));
	if(node==NULL)
	{
		return false;
	}
	node->data=data;//对创建的栈节点赋初值
	node->next=NULL;
	struct Node *tra=L;
	while(tra->next!=NULL)//遍历找到尾部
	{
		tra=tra->next;
	}
	tra->next=node;//将上面创建的节点和尾节点链接
	L->top++;
	return true;
}
//出栈
bool pop(struct Node *L,int *data)
{
	if(is_empty(L))
	{
		return false;
	}
	//第一种方式可以通过top,之后遍历链表找到尾结点
	//第二种方式可以通过两个个指针,遍历完之后,一个指向尾结点的前一个结点,一个指向尾结点
	struct Node *tra=L;//采用第二种方法
	struct Node *temp=L->next;
	while(temp->next!=NULL)
	{
		tra=tra->next;
		temp=temp->next;
	}
	tra->next=NULL;
	*data=temp->data;
	free(temp);//释放栈顶元素
	return true;
}


int main()
{
	struct Node *stack=Stack_Create();
	push(stack,10);
	push(stack,20);
	int value;
	pop(stack,&value);
	printf("出栈的数据:%d\r\n",value);
	return 0;
}

今天有些累了,明天继续

相关推荐
WL学习笔记10 小时前
堆(数据结构)
数据结构·
wabs66614 小时前
关于图论【卡码网100.最大岛屿的面积的思考】
数据结构·算法·图论
yuannl1016 小时前
图的最短路径Dijkstra
数据结构
zander25817 小时前
138. 随机链表的复制
数据结构·算法·链表
过期动态17 小时前
【LeetCode 热题 100】找到字符串中所有字母异位词
java·数据结构·算法·leetcode·职场和发展·rabbitmq
来一碗刘肉面17 小时前
栈在递归中的应用
数据结构·算法
皓月斯语18 小时前
程序设计语言的特点
开发语言·数据结构·c++
邪修king18 小时前
C++ 进阶终章:异常机制与智能指针全解 —— 从错误处理到 RAII 资源管理,打通现代 C++ 的核心命脉
android·数据结构·c++
Adios7941 天前
设置交集大小至少为2
数据结构·算法·leetcode
来一碗刘肉面1 天前
栈的应用(表达式求值)
数据结构·算法