八大数据结构类型总结及应用 数组 栈 队列 链表(上)

数据结构八大类型的总结及应用(上)

本篇博客只总结了一半的内容,后一半的链接给各位送上:
https://blog.csdn.net/weixin_44593531/article/details/107453932

数组

概念及优缺点

数组是可以再内存中连续存储多个元素的结构,在内存中的分配也是连续的,数组中的元素通过数组下标进行访问。

优点十分明显,根据数组的索引可以快速的查找元素和遍历数组。

缺点表现在以下三个方面:

  1. 数组的大小一般在创建的时候就已经定义好了。
  2. 数组的添加某个元素,和删除某个元素的操作比较复杂,需要修改该位置后面的所有元素。
  3. 数组只能存放一种类型的数据。

在这里插入图片描述

数组的应用

我们通过一个C语言程序来总结数组结构的适用范围

对一个数组进行冒泡排序和选择排序

int main()
{
	int a[] = {2,5,8,0,9,6};
	int n= sizeof(a)/sizeof(a[0]); 
	//冒泡排序从大到小 
	for(int i=0;i<n-1;i++)
	{
		for(int j=0;j<n-1-i;j++){
			if(a[j]<a[j+1]){
				int x = a[j];
				a[j] = a[j+1];
				a[j+1] = x;
			}
		}
	}
	//选择排序从小到大 
	int tmp = 0;
    for (int i=1;i<n;i++) {
        int j = i - 1;
        if (a[i] < a[j]) {
            tmp = a[i];
            a[i] = a[j];
            while (tmp < a[j-1]) {
                a[j] = a[j-1];
                j--;
            }
            a[j] = tmp;
        }
    }
	return 0;
} 

我们可以看到,如果在实现需要频繁的迅速的遍历或者查找元素功能,且很少增加和删除的情况下,数组是非常有效的。但是通过对概念的了解,数组存放在一片连续的地址空间上,因而一般用来处理数量相对较小的数据,也就是对内存空间要求不大时,我们使用数组来操作。

概念

栈是一种特殊的线性表,仅能在线性表的一端操作,栈顶允许操作,栈底不允许操作。 栈的特点是:先进后出,或者说是后进先出,从栈顶放入元素的操作叫入栈,取出元素叫出栈。
在这里插入图片描述

应用

用C语言链表来实现栈操作

typedef struct Link{
	int elem;
	struct Link *next;
}link;//结构体创建 

link * initStack(){
	link * stack = (link*)malloc(sizeof(link));
	return stack;
}//新建一个栈 ,令其指针永远指向栈顶元素,元素的指针指向下一元素 

void inStack(int elem, link *stack) {
	link *temp = stack;
	if(temp->next == NULL){//如果栈内没有元素就直接添加到栈顶 
		link * d = (link*)malloc(sizeof(link));
		d = temp->next;
		d->elem = elem;
		d->next = NULL;
	}else{//否则添加到栈顶,并将新元素指向之前的栈顶 
		link * s = (link*)malloc(sizeof(link));
		s->next = temp->next
		temp->next = s;
		s->elem = elem;
	}
}//入栈 

void outStack(link *stack){
	link *temp = stack;
	if(temp->next == NULL){
		printf("The stack is empty!");
	}else{
		printf("%d",temp->next);
	}
}//输出栈顶元素 

void deleteStackElem(link *stack){
	link *temp = stack;
	if(temp->next == NULL){
		printf("The stack is empty!");
	}else{
		link *s = temp->next;
		temp->next = s->next;
		s->next = NULL;
		free(s);
	}
}//删除栈顶元素 

队列

概念

队列与栈一样,也是一种线性表,不同的是,队列可以在头一端添加元素,在尾一端取出元素,也就是:先进先出。从一端放入元素的操作称为入队,取出元素为出队。
在这里插入图片描述

typedef struct Link{
	int elem;
	struct Link *next;
}link;//结构体创建 

link * initQueue{
	link *front = (link*)malloc(sizeof(link));
	link *rear = (link*)malloc(sizeof(link));
} //初始化两个指针分别指向入队口和出队口 

void addElem(int elem,link *front,link *rear){
	link *add = (link*)malloc(sizeof(link));
	link *temp = rear;
	if(temp->next == NULL){
		temp->next = add;
		add->next = elem;
		front->next = add;
	} else{
		temp->next->next = add;
		add->elem = elem;
		temp->next = add;
	}
}//入队 

void delElem(link *front,link *rear){
	link *temp = front;
	if(temp->next == NULL){
		printf("The queue is empty!");
	}else{
		link *elem = temp->next
		temp->next = elem->next;
		free(elem);
	}
}//出队 

链表

概念及优缺点

链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,根据指针的指向,链表能形成不同的结构,例如单链表,双向链表,循环链表等。

单链表:
每一个结点被分成两个部分,第一个部分是用来存放数据的,称为数据域,第二个部分是用来存放指针的,称为指针域,该位置所存放的指针指向的是下一个结点的地址。

一般链表中都存在一个头结点,该结点是不存放数据的,也就是说该结点的数据域为NULL,另外还存在一个尾结点,这个结点的指针域为空,也就是不指向下一个结点,因为它不存在下一个。首元结点指的是第一个存放数据的结点,头指针指向的是头结点。
在这里插入图片描述

双向链表:
在传统链表中我们寻找下一个结点是否方便,但是如果要追溯前面的结点是比较困难的。因此双向链表提供了反向遍历的能力。其秘密在于每个结点有两个指向其他结点的引用,一个指向前继结点,一个指向后继结点。下图显示了双向链表:在这里插入图片描述
每个结点包括前指针、数据、后指针三部分。前指针指向前一个结点,后指针指向后一个结点,对于头结点,前指针为NULL,对于尾结点来时后指针为NULL。

循环链表:
循环链表就是在单链表的基础上,尾结点指向头结点,如下图所示:
在这里插入图片描述

链表的优点:

  • 方便添加和删除元素

链表的缺点

  • 查找相对困难

链表的应用及适用范围

C语言对单链表进行增删改查操作:

typedef struct Link{
	int elem;
	struct Link *next;
}link;//创建结构体

link * initLink(int n){
	int x;
    link * p=(link*)malloc(sizeof(link));
    link * temp=p;
    for (int i=0; i<n; i++) {
        link *a=(link*)malloc(sizeof(link));
        scanf("%d",&x);
        a->elem=x;
        a->next=NULL;
        temp->next=a;
        temp=temp->next;
    }
    return p;
} //新建

void addElem(int elem, int index,link *p) {
	link *temp = p;
	link *a=(link*)malloc(sizeof(link));
	for(int i=0;i<index;i++){
		temp = temp->next;
	}
	a->elem = elem;
	a->next = temp->next;
	temp->next = a;
}//增加 

link * delElem(link * p,int add){
    link * temp=p;
    for (int i=0; i<add; i++) {
        temp=temp->next;
    }
    link * del=temp->next;
    temp->next=temp->next->next;
    free(del);
    return p;
}//删除 

void modifyElem(link *p,int index,int elem){
	link *temp = p;
	for(int i = 0;i<index;i++){
		temp = temp->next;
	}
	temp->elem = elem;
} 

void getElem(link *p, int index){
	link *temp = p;
	for(int i = 0;i<index;i++){
		temp = temp->next;
	}
	printf("%d\n",temp->elem);
} //查找 

void display(link *p){
	link *temp=p;
	while(temp){
		printf("%d",temp->next->elem);
		temp=temp->next;
	}
	printf("\n");
}//遍历 

我们可以看到,在链表的初始化中不需要确定容量,所以后面可以进行元素的增加和删除,而且删除和增加操作都非常方便只需要改变指针所指向的值就好,但是,链表的查找却不是很简单,因为他需要从头结点开始遍历一直到找到该数据,相比数组而言,无法通过索引进行寻找,因此,我们一般在需要频繁的增加和删除的情况下使用链表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值