数据结构总结

 

 

数据结构总结_第1张图片 

什么是数据结构

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

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

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

2.1 逻辑关系

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

1)线性关系

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

2)树形关系

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

 3)图形关系

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

 

2.2 存储关系

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

1)顺序存储

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

2)链式存储

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

 本文重点

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

1、单链表

 

//单链表
#include
#include
#include
#include
//结点的创建
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 || iname,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;
}

输出如下

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、循环单链表

//循环单链表
#include
#include
#include
#include
//结点的创建
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 || iname,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;
}

输出

//头插法插入数据
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开始。

 

//顺序栈
#include
#include
#include
#include
#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.链栈

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

今天有些累了,明天继续

你可能感兴趣的:(数据结构)