线性表(长篇多图附代码)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/BluseLIBB/article/details/99343774

数据结构-线性表

  • 线性表

    线性表(其中一种数据结构,属于逻辑结构):具有相同特征的数据,数据之间是一种先后有序序列
    具有线性关系的数据集合,一个数据前有另一个数据,在之后还有一个数据(对于一个数据来说,和它有直接关系的只有之前的这个数据(前驱),之后的一个数据(后继));同时第一个数据之前没有,最后一个数据之后也没有;把数据叫做元素

    线性表中每个元素只有一个前驱,一个后继

    线性表能够实现的运算:
    1、创建
    2、清空
    3、插入
    4、删除
    5、求表长
    6、表为空
    7、查询
    8、修改

    图 《数据结构C语言版》page 6
    在这里插入图片描述
    顺序存储<------------>链式存储 数组<------------>指针
    一个地址是连续的,一个是不连续的由malloc时随机分配地址

  • 1,顺序表

    顺序表:线性表的顺序存储(具备线性关系)(逻辑结构是线性结构,存储结构是顺序存储)
    顺序表是线性表的一种(是线性表采用顺序存储的方式在计算机中表示)
    顺序存储:开辟一段连续的内存空间,用来存储具备一种逻辑结构的数据集合

    在使用顺序表进程存储时,这段连续空间地址的大小就是线性表的元素序列的顺序(存储的地址的高低就是序列前驱后继的顺序),地址就能表示线性表(顺序表)的关系
    顺序表中,需要提前指定连续空间的大小,通过下标的值能够表示前驱后继,通常需要有一个整数表示顺序表最后一个元素位置

    顺序表实现的运算和线性表一样

     //数据结构形式
     #define SIZE 10
     typedef int data_t;
     typedef struct array
     {
     	data_t data[SIZE];//size整段連續空間的長度
     	int length;//順序表當前存儲數據的長度
     }ARRAY, *ARRAYP;
     //增删改查
     ARRAYP create_array();
     void clear_array(ARRAYP p);
     void insert_array(ARRAYP p,int pos,data_t num);
     void delete_array(ARRAYP p,int pos);
     int empty_array(ARRAYP p);
     int full_array(ARRAYP p);
     data_t search_array(ARRAYP p,int pos);
     void update_array(ARRAYP p,int pos,data_t num);
     void show_array(ARRAYP p);
    

    具体实现

     //创建
     ARRAYP create_array()
     {
     	ARRAYP p = malloc(sizeof(ARRAY));//申请空间
     	if(p =\= NULL)
     	{
     		printf("malloc error\n");
     		return NULL;
     	}
     	p->length = 0;//初始化长度
     	bzero(p->data,sizeof(data_t)*SIZE);//清空
     	return p;
     } 
     //清空
     void clear_array(ARRAYP p)
     {
     	if(p == NULL)
     	{
     		printf("struct array is NULL\n");
     		return;
     	}
     	bzero(p->data,sizeof(data_t)*SIZE);
     	p->length = 0;
     } 
    

在这里插入图片描述

//插入
void insert_array(ARRAYP p,int pos,data_t num)
{
	//判断是否存在
	if(p == NULL)
	{
		printf("array is NULL\n");
		return ;
	}
	//判满
	if(full_array(p))
	{
		printf("array is full\n");
		return ;
	}
	//判断插入位置是否越界
	if((p->length+1) < pos)
	{
		printf("insert pos error\n");
		return ;
	}
	int i;
	//将插入位置后的数据全部向后移动一位
	for(i = p->length ; i > pos-1 ; i--)
	{
		p->data[i] = p->data[i-1];
	}
	//插入数据
	p->data[pos-1] = num;
	p->length++;
}

在这里插入图片描述

//删除
void delete_array(ARRAYP p,int pos)
{
	//判断删除位置是否越界
	if(pos > p->length)
	{
		printf("delete pos is error\n");
		return ;
	}
	//判空
	if(empty_array(p))
	{
		printf("delete is empty\n");

		return ;
	}
	int i;
	//将删除位置之后的数据依次向前移动
	for(i = pos-1;i < p->length-1; i++)
	{
		p->data[i] = p->data[i+1];
	}
	p->length--;
}
//判断是否为空
int empty_array(ARRAYP p)
{
	return p->length =\= 0?1:0;
}
6、判断是否为满
int full_array(ARRAYP p)
{
	return p->length == SIZE?1:0;
}
//遍历整个数组
data_t search_array(ARRAYP p,int pos)
{
	if(pos > p->length)
	{
		printf("search pos is error\n");
		return 0;
	}
	return p->data[pos-1];
} 
//找到位置,直接修改值
void update_array(ARRAYP p,int pos,data_t num)
{
	if(pos > p->length)
	{
		printf("update pos is error\n");
		return ;
	}

	p->data[pos-1] = num;
} 
//遍历并显示
void show_array(ARRAYP p)
{
	int i;
	for(i = 0;i < p->length;i++)
	{
		printf("%d ",p->data[i]);
	}
	printf("\n");
}
  • 2.链表

    图《C和指针》 page 235
    在这里插入图片描述

    链表:线性表的离散(链式)存储
    把线性表中的所有元素存储在不同的区域,通过指针或地址建立数据元素之间的关系,把这种线性表叫做链表

    离散(链式)存储:在进行存储时每个元素存放位置相互之间都是没有直接联系的,内存开辟都是单独的一个数据进行,单独的一个个数据分开进行存储,元素的地址不一定连续,地址之间不是表示数据关系的

    在链表中,每个元素不只是存储数据还应该存储下一个元素的地址,人为的创造数据之间的关系
    链表中数据元素(数据元素和指针)-------结点

    链表中的每个结点是单独创建,只需要知道结点的结构就能知道链表的样式
    ①单链表
    单链表:链表中的结点只有一个指针,这个指针就一定要表示数据结点的关系,需要指向结点的后继(表示有序序列)

     typedef int data_t;
     typedef struct node
     {
     	data_t data;//数据域
     	struct node * next;//指針域
     }NODE,*NODEP;
     NODEP create_list();
     void clear_list(NODEP head);
     void insert_list(NODEP head,int pos,data_t num);
     void delete_list(NODEP head,int pos);
     int search_list(NODEP head,data_t num);
     void update_list(NODEP head,int pos,data_t num);
     void show_list(NODEP head);
     int empty_list(NODEP head);
     
     //创建链表
     NODEP create_list()
     {
     	NODEP head = malloc(sizeof(NODE));//创建头节点
     	head->next = NULL;//head->data头结点不能被操作
     	return head;
     }
    

    在这里插入图片描述

     //插入节点
     void insert_list(NODEP head,int pos,data_t num)
     {
     	NODEP p = head;
     	int i = 0;
     	while(p->next != NULL)
     	{
     		i++;//用来计算位置
     		if(i =\= pos)//判断是否达到要插入的位置
     		{
     			break;
     		}
     		p = p->next;
     	}
     	NODEP q = malloc(sizeof(NODE)); //申请一个节点
     	if(q == NULL)
     	{
     		printf("insert malloc error\n");
     		return ;
     	}
     	//进行插入操作的插入操作的指针交换   如上图所示
     	q->data = num;
     	q->next = p->next;
     	p->next = q;
     }
    

    在这里插入图片描述

     //删除节点
     void delete_list(NODEP head,int pos)
     {
     	if(head =\= NULL)
     	{
     		printf("list is erorr\n");
     		return ;
     	}
     	if(empty_list(head))
     	{
     		printf("list is empty\n");
     		return;
     	}
     	NODEP p = head;
     	int i = 0;
     	while(p->next != NULL)
     	{
     		i++;
     		//找到pos并释放
     		if(i =\= pos)
     		{
     			NODEP q = p->next;
     			p->next = q->next;//指针交换
     			printf("delete num is %d\n",q->data);
     			free(q);//释放空间
     			break;
     		}
     		p = p->next;
     	}
     }
     //遍历 找到num 返回节点位置 否则返回0
     int search_list(NODEP head,data_t num)
     {
     	NODEP p = head->next;
     	int i = 0;
     	while(p !=  NULL)
     	{
     		i++;
     		if(p->data =\= num)
     		{
     			return i; 
     		}
     		p = p->next;
     	}
     	return 0;
     }
     //更新节点   
     void update_list(NODEP head,int pos,data_t num)
     {
     	NODEP p = head;
     
     	int i = 0;
     	while(p->next!= NULL)//判断下一个节点是否存在
     	{
     		i++;
     		p = p->next;
     		if(i =\= pos)//找到节点并修改值
     		{
     			p->data = num;
     			break;
     		}
     	}
     }
     
     void show_list(NODEP head)
     {
     	NODEP p = head->next;
     	while(p != NULL)//表示節點存在
     	{
     		printf("%d ",p->data);
     		p = p->next;
     	}
     	printf("\n");
     }
     
     int empty_list(NODEP head)
     {
     	return head->next == NULL?1:0;
     }
     
     void clear_list(NODEP head)
     {
     
     	NODEP p = head->next;
     	while(p != NULL)
     	{
     		NODEP q = p;
     		p = p->next;
     		free(q);
     	}
     	head->next = NULL;
     }
    

    ②双链表
    图《C和指针》 page 245
    在这里插入图片描述
    typedef struct NODE{
    struct NODE *fwd;//指针域
    struct NODE *bwd;
    int value;//数据域
    } Node;
    在这里插入图片描述

     //插入节点
     void insert_list(NODEP head,int pos,data_t num)
     {
     	NODEP p = head;
     	int i = 0;
     	while(p->next != NULL)
     	{
     		i++;//计数
     		if(i =\= pos)//找到位置
     		{
     			break;
     		}
     		p = p->next;
     	}
     	NODEP q = malloc(sizeof(NODE)); //申请节点空间
     	if(q == NULL)
     	{
     		printf("insert malloc error\n");
     		return ;
     	}
     	//指针交换
     	q->data = num;
     	NODEP G = p->next;
     	q->next = p->next;
     	q->forward = p;
     	if(p->next != NULL) 
     	{
     		G->forward = q; //p->next->forward = q;
     	}
     	p->next = q;
     
     }
    

    在这里插入图片描述

     //删除节点
     void delete_list(NODEP head,int pos)
     {
     	if(head =\= NULL)
     	{
     		printf("list is erorr\n");
     		return ;
     	}
     	if(empty_list(head))
     	{
     		printf("list is empty\n");
     		return;
     	}
     	NODEP p = head;
     	int i = 0;
     	while(p->next != NULL)
     	{
     		i++;
     		if(i == pos)
     		{
     			NODEP q = p->next;
     			p->next = q->next;
     			q->next->forward = p;
     			printf("delete num is %d\n",q->data);
     			free(q);
     			break;
     		}
     		p = p->next;
     	}
     }
    

    ③单向循环链表
    图《数据结构C语言版》 page 35
    在这里插入图片描述
    单链表中最后一个结点的next指针域不在是为空,用来存储第一个结点的地址,形成循环

    ④双向循环链表
    图《数据结构C语言版》 page 36
    在这里插入图片描述

     NODE * create()
     {
     	//空双向循环列表
     	NODE * head = malloc(sizeof(NODE));
     	head->forward = head;
     	head->next = head;
     	return head;
     }
     
     void insert(NODE * head,int num)
     {
     	NODE * q = malloc(sizeof(NODE));
     	q->data = num;
     	NODE * p = head->forward;
     	q->next = p->next;
     	q->forward = p;
     	p->next->forward = q;
     	p->next = q;
     }
     
     void delete(NODE * head)
     {
     	NODE * p = head;
     	NODE * q = p->next;
     	p->next = q->next;
     	p->next->forward = p;
     	free(q);
     }
    

2.堆栈 队列
1.栈 Last-In First-Out LIFO
在这里插入图片描述
栈:是一种线性表,是只允许在表中一端进行插入删除操作,另一端不能进行任何操作的线性表
栈特点:是一种先进后出的线性表
能够进行操作的一端叫做栈顶,不能进行操作的一端叫做栈底,进行插入操作叫做入栈(压栈),进行删除操作叫做出栈(弹栈)
在栈中,存在一个栈顶指针指向当前的栈顶位置,通过固定栈底位置去实现,在栈中栈顶栈底的位置是有可能发生变换,是一种动态的过程

①顺序存储(顺序栈)
在这里插入图片描述
在顺序栈中top指针指向的位置不同它的代码方式也是不同,一开始top指向栈中栈底第一个数据位置(top==0,这是可以作为判空条件)但编写的代码一定按照top指针指向位置为空数据进行判断
也可以(top == -1作为判空条件),top指向的位置里面一定是存储了数据

#define SIZE 10
typedef int data_t;
typedef struct node
{
	data_t data[SIZE];//size整段連續空間的長度
	int length;//順序表當前存儲數據的長度
}NODE, *NODEP;

NODEP create_stack()
{
	NODEP p = malloc(sizeof(NODE));
	if(p == NULL)
	{
		printf("malloc error\n");
		return NULL;
	}
	p->length = 0;
	bzero(p->data,sizeof(data_t)*SIZE);
	return p;
}

在这里插入图片描述

	//压栈
	void push_stack(NODEP top, data_t num)
	{
		if(full_stack(top))
		{
			printf("栈区已满\n");
			return ;
		}
		top->data[top->length]=num;
		top->length++;
	}
	//出栈
	void pop_stack(NODEP top)
	{
		if(empty_stack(top))
		{
			printf("栈区已空\n");
			return ;
		}
	top->length--;
		printf("清空栈顶%d",top->data[top->length]);
	}

②链式存储(链式栈)
在这里插入图片描述
栈中数据之间是离散的,所以使用指针来找到数据之间的关系;每个结点都有两个区域(数据域、指针域)
在链式栈进行入栈出栈操作时,新的栈顶要存放原先栈顶的地址
链式栈的操作就是链表的头插法

typedef struct node
{
	int data;
	struct node * next;

}NODE,*NODEP;

NODEP create_stack();
void push_stack(NODEP top,int data);
void pop_stack(NODEP top);
int empty_stack(NODEP top);
int top_stack(NODEP top);
void show_stack(NODEP top);

NODEP create_stack()
{
	NODEP top = malloc(sizeof(NODE));
	if(top == NULL)
	{
		printf("create stack error\n");
		return NULL;
	}
	top->next = NULL;
	return top;
}

在这里插入图片描述

//压栈
void push_stack(NODEP top,int data)
{
	if(top == NULL)
	{
		return ;
	}
	NODEP p = malloc(sizeof(NODE));
	p->data = data;
//在沒有進行入棧操作前,當時的棧頂指針中存儲的是當時的棧頂元素,所以需要先把原棧頂元素的地址保存在新的棧頂元素的next指針域
	
	p->next = top->next;
	top->next = p;
}

void pop_stack(NODEP top)
{
	if(top == NULL)
	{
		return ;
	}
	if(empty_stack(top))
	{
		printf("stack is empty\n");
		return ;
	}
	NODEP p = top->next;
	top->next = p->next;
	printf("pop data is %d\n",p->data);
	free(p);
}

int empty_stack(NODEP top)
{
	return top->next == NULL?1:0;
}

int top_stack(NODEP top)
{
	if(empty_stack(top))
	{
		printf("stack is empty\n");
		return -1;
	}
	return top->next->data;
}

void show_stack(NODEP top)
{
	NODEP p = top->next;
	while(p != NULL)
	{
		printf("%d ",p->data);
		p = p->next;
	}
	printf("\n");
}

2.队列
在这里插入图片描述
特点:先进先出 First-In First-Out FIFO
队列(线性表):是一种特殊线性表,限制在线性表的两端进行操作(插入、删除);其中一端进行删除操作,另一端进行插入操作,把删除的一端叫做队头,把删除操作叫做出队,把插入的一端叫做队尾,把插入操作叫做入队。是一种先进先出的特点FIFO
队列进行操作时,由于设置的是在表的两端,所以需要两个指针分别指向表的两端(队头、队尾)
队头指针
队尾指针

队列中,进行删除操作时,每个队头结点需要找到下一次队头结点(新的队头结点);进行插入操作时,原队尾结点能够获取到新队尾结点的地址

①链式存储(链式队列)

链式队列其实就是添加了尾指针的链表

typedef struct node
{
	int data;
	struct node * next;
}NODE,*NODEP;

typedef struct point
{
	NODEP front;
	NODEP rear;
}linkqueue,*linkqueueP;

linkqueueP create_queue();
void insert_queue(linkqueueP p,int data);
void delete_queue(linkqueueP p);
int empty_queue(linkqueueP p);
void show_queue(linkqueueP p);

linkqueueP create_queue()
{
	linkqueueP p = malloc(sizeof(linkqueue));
	p->front = p->rear = malloc(sizeof(NODE));
	p->front->next = NULL;
	return p;
}

在这里插入图片描述

void insert_queue(linkqueueP p,int data)
{
	NODEP q = malloc(sizeof(NODE));
	q->data = data;
	q->next = NULL;
	p->rear->next = q
	p->rear = q;
}

在这里插入图片描述

void delete_queue(linkqueueP p)
{
	if(empty_queue(p))
	{
		printf("queue is empty\n");
		return;
	}
	NODEP q = p->front->next;
	p->front->next = q->next;
	printf("delete data is %d\n",q->data);
	if(q->next == NULL)
	{
		p->rear = p->front;
	}
	free(q);
}

int empty_queue(linkqueueP p)
{
	return p->front->next == NULL?1:0;
}

void show_queue(linkqueueP p)
{
	NODEP q = p->front;
	while(q->next != NULL)
	{
		q = q->next;
		printf("%d ",q->data);
	}
	printf("\n");
}

②顺序存储(顺序队列–循环队列)
在这里插入图片描述
队头指针和队尾指针如果指向相同的一个位置,作为判断这个队列为空的条件,这时:
队尾指针的含义,即将在这个位置插入数据
队头指针的含义,即将要在这个位置删除数据

typedef struct queue
{
	int *data;//用來存儲一段連續空間的首地址
	int length;//用來存儲數據的個數
	int front;//隊頭指針
	int rear;//隊尾指針
}SEQUEUE;

SEQUEUE * create_queue();
void insert_queue(SEQUEUE * queue,int data);
void delete_queue(SEQUEUE * queue);
int empty_queue(SEQUEUE * queue);
int full_queue(SEQUEUE * queue);
void show_queue(SEQUEUE * queue);
,
SEQUEUE * create_queue()
{
	SEQUEUE * queue = malloc(sizeof(SEQUEUE));
	scanf("%d",&queue->length);
	queue->data = malloc(sizeof(int)*(queue->length));//自定义队列的长度
	queue->front = queue->rear = 0;
	return queue;
}

在这里插入图片描述

//入队操作
void insert_queue(SEQUEUE * queue,int data)
{
	if(full_queue(queue))
	{
		printf("queue is full\n");
		return;
	}
	queue->data[queue->rear] = data;
    //队尾指针移动,+1%是为了实现循环
	queue->rear = (queue->rear+1)%queue->length;
}

void delete_queue(SEQUEUE * queue)
{
	if(empty_queue(queue))
	{
		printf("queue is empty\n");
		return ;
	}
	printf("front data is %d\n",queue->data[queue->front]);
	//对头指针移动
	queue->front = (queue->front+1)%queue->length;
}

在这里插入图片描述

int empty_queue(SEQUEUE * queue)
{
	//如果对头指针指向相同地址,则为最初状态,队列为空
	return queue->front == queue->rear?1:0;
}

在这里插入图片描述

int full_queue(SEQUEUE * queue)
{
	//如果队尾指针+1和对头指针相同,则表示堆满
	return queue->front == (queue->rear+1)%queue->length?1:0;
}

void show_queue(SEQUEUE * queue)
{
	int i = queue->front;
	while(i != queue->rear)
	{
		printf("%d ",queue->data[i]);
		i++;
	}
	printf("\n");
}

猜你喜欢

转载自blog.csdn.net/BluseLIBB/article/details/99343774