数据结构(顺序表和链表)

线性表   

        线性表是n个具有相同特性的数据元素的有限序列。
        常见的线性表:顺序表、链表、栈、队列

        线性表在逻辑上是线性结构,连续的一条直线。但是在物理存储结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

顺序表

        顺序表是线性表的一种,使用一串物理地址连续的存储单元来存储数据元素。

        缺点:
        (1)当数据量大时,插入和删除操作麻烦,需要移动大量大元素;
        (2)采用数组实现的连续存储,需要先预估数组的大小,是固定的。
        优点:
        (1)因为有下标,查找速度快;
        (2)可以实现随机访问。

静态顺序表

#include <stdio.h>
#include <stdlib.h>
#define N 100
typedef struct
{
	int data[N];
	int last;
}seqList_t;
//1. 创建一个空的顺序表 createEmpty()
seqList_t* createEmpty()
{
	seqList_t* p = (seqList_t*)malloc(sizeof(seqList_t));
	if(p == NULL)
	{
		printf("create failed!!!\n");
		return NULL;
	}
	p->last = 0;
	return p;
}
//2. 判断一个顺序表是否为空 空的话返回1 不空返回 0 isEmpty()
int isEmpty(seqList_t* p)
{
	return p->last == 0;
}
//3. 判断一个顺序表是否为满 满的话返回1 不满返回 0 isFull()
int isFull(seqList_t* p)
{	
	return p->last == N;
}
//4. 遍历顺序表中所有有效元素 showSeqlist()
void showSeqlist(seqList_t* p)
{
	int i;
	for(i = 0;i < p->last;i++)
	{
		printf("%d ",p->data[i]);
	}
	printf("\n");
}
//5. 在指定位置插入数据 insertInto(),成功返回1,否则返回0
int insertInto(seqList_t* p,int post,int value)
{
	int i;
	if(post <= 0 || post > p->last+1 || isFull(p))
	{
		printf("insert failed\n");
		return 0;
	}		
	for(i = p->last-1;i >= post-1;i--)
	{
		p->data[i+1] = p->data[i];
	}
	p->data[post-1] = value;
	p->last++;
	return 1;
}
//6. 删除指定位置上数据 deleteFrom()
int deleteFrom(seqList_t* p,int post)
{
	int i;
	if(post <= 0 || post > p->last ||isEmpty(p))
	{
		printf("delete failed\n");
		return 0;
	}	
	for(i = post-1;i <= p->last-1;i++)
	{
		p->data[i] = p->data[i+1];
	}
	p->last--;
	return 1;
}
//7. 求顺序表的长度 getLength()
int getLength(seqList_t* p)
{
	return p->last;
}

//8. 查找某个元素出现在顺序表中的位置 findData()	找不到返回0
int findData(seqList_t* p,int value)
{
	int i;
	for(i = 0;i <= p->last-1;i++)
	{
		if(p->data[i] == value)
		{
			return i;
		}
	}
	return -1;
}
//9. 清空顺序表clearSeqlist()
void clearSeqlist(seqList_t* p)
{
	p->last = 0;
}

int main()
{
	seqList_t* p = createEmpty();
	if(NULL == p)
		return -1;
	insertInto(p,1,33);
	insertInto(p,2,44);
	insertInto(p,3,55);
	insertInto(p,2,1000);
	showSeqlist(p);
	deleteFrom(p,1);
	showSeqlist(p);
	int x = 1000;
	int index = findData(p,x);
	index==-1?printf("未找到%d\n",x):printf("%d index is %d\n",x,index+1);
	free(p);
	return 0;
}

链表 

        线性表的链式存储称为链表。
         缺点:
        (1)查找速度慢;
        (2)不可以实现随机访问。
        优点:
        (1)插入和删除操作很方便,因为不需要移动大量大元素;
        (2)不需要先预估存储大小,没有满的状态。
       

单向链表(带头结点)

#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
    int data;			//数据域
    struct node* next;	//指针域,指向下一个结点的首地址
}linknode_t;
/*创建有头结点空的链表*/
linknode_t* creatEmpty()
{
    linknode_t *phead=(linknode_t*)malloc(sizeof(linknode_t));
    if(phead==NULL)
    {
        printf("malloc failed\n");
        return NULL;
    }
    phead->next=NULL;	//将指针域置空
    					//数据域不用赋值 因为头结点数据无效
    return phead;		//将链表在堆区的首地址返回
}
/*遍历有头单向链表*/
void show(linknode_t *p)
{
    while(p->next!=NULL)
    {
        p=p->next;//跨过头结点
        printf("%d ",p->data);
    }
    printf("\n");
}
/*求链表的长度(不包含头结点)*/
int getLength(linknode_t *p)
{
    int length=0;
    while(p->next!=NULL)
    {
        p=p->next;
        length++;
    }
    return length;
}
/*在链表的指定位置插入数据*/
int insertInto(linknode_t *p,int post,int x)
{
    if(post<=0||post>getLength(p)+1)
    {
        printf("insert failed\n");
        return -1;
    }
    //插入位置合理,创建一个新的结点存储数据
    linknode_t *pnew=(linknode_t*)malloc(sizeof(linknode_t));
    if(pnew==NULL)
    {
        printf("pnew malloc failed\n");
        return -1;
    }
    pnew->data=x;
    pnew->next=NULL;
    //将头指针移动到插入位置的前一个位置
    int i=0;
    for(i=0;i<post-1;i++)
    {
        p=p->next;
    }
    //将新结点连接到链表上(先连后面,再连前面)
    pnew->next=p->next;
    p->next=pnew;
    return 0;
}
/*判断链表是否为空*/
int isEmpty(linknode_t *p)
{
    return p->next==NULL;
}
/*删除指定位置上的数据*/
int deleteFrom(linknode_t *p,int post)
{
    if(post<=0||isEmpty(p)||post>getLength(p))
    {
        printf("delete filed\n");
        return -1;
    }
    int i;
    for(i=0;i<post-1;i++)
    {
        p=p->next;
    }
    linknode_t *pdel=p->next;	//定义一个指针指向被删除节点
    p->next=pdel->next;			//跨过删除节点指向下一个节点
    free(pdel);					//释放删除节点在堆区空间
    pdel=NULL;					//避免野指针
    return 0;
}
/*查找数据出现在链表中的位置*/
int findData(linknode_t *p,int n)
{
    int post=0;
    while(p->next!=NULL)
    {
        p=p->next;
        post++;
        if(p->data==n)
        {
            return post;
        }
    }
    return -1;
}
/*清空链表*/
void clear(linknode_t *p)
{
	linknode_t *pdel = NULL;
    while(p->next!=NULL)
    {
        pdel = p->next;//创建一个指针指向被删除节点
        p->next = pdel->next;
        free(pdel);
        pdel = NULL;
    }
}
int main(int argc, const char *argv[])
{
    linknode_t *p=creatEmpty(p);
    if(p==NULL)
    {
        printf("p is NULL");
        return -1;
    }
    show(p);
    printf("length is %d\n",getLength(p));
    printf("%d\n",isEmpty(p));
    insertInto(p,1,11);
    insertInto(p,2,22);
    insertInto(p,3,33);
    insertInto(p,4,44);
    insertInto(p,5,55);
    show(p);
    insertInto(p,3,1000);
    show(p);
    deleteFrom(p,3);
    show(p);
    int res=findData(p,22);
    if(res==-1)
    {
        printf("不存在\n");
    }
    else
    {
        printf("%d\n",res);
    }
    clear(p);
    show(p);
    printf("length is %d\n",getLength(p));
    free(p);
    return 0;
}

单向循环链表(首尾相连的环)

        链表最后一个结点上存储了第一个结点的地址,就成为单向循环链表。

单向链表的应用

(1)尾插法

        每次都是在链表的最后一个结点的最后一个位置进行插入操作。

(2)约瑟夫问题(循环杀死猴子,找到最后的猴王)

#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
	int data;
	struct node *next;
}linklist_t;
int main()
{
	int all_num;	//猴子总数
	int start_num;	//开始报数的猴
	int kill_num;	//数到几杀死一个猴
	printf("请输入总数 开始报数的猴 数到几杀死一个猴\n");
	scanf("%d%d%d",&all_num,&start_num,&kill_num);
	//将1-8使用尾插法形成一个环(无头)
	linklist_t* phead = (linklist_t*)malloc(sizeof(linklist_t));
	if(NULL == phead)
	{
		printf("phead malloc failed\n");
		return -1;
	}	
	phead->data = 1;
	phead->next = NULL;
	linklist_t* ptail = phead;	//只有一个结点,既是头也是尾
	//2-8用尾插连到1后面
	int i;
	for(i = 2;i <= 8 ;i++)
	{	
		linklist_t* pnew = (linklist_t*)malloc(sizeof(linklist_t));
		if(NULL == pnew)
		{
			printf("pnew malloc failed\n");
			return -1;
		}
		pnew->data = i;
		pnew->next = NULL;
		ptail->next = pnew;
		ptail = pnew;	//新结点变成尾结点
	}
	ptail->next = phead;    //将首尾相连形成环
	//将头指针移动到开始报数的猴子身上
	for(i = 0;i < start_num-1;i++)
	{
		phead = phead->next;
	}	
	linklist_t* pdel = NULL;
	//循环杀猴
	while(phead != phead->next)	//只剩下一只猴的时候结束循环
	{
		//将头指针移动到删除位置的前一个位置
		for(i = 0;i < kill_num-2;i++)
		{
			phead = phead->next;
		}		
		pdel = phead->next;	                    //定义指针指向被删除结点
		phead->next = pdel->next;               //跨过删除结点	
		printf("%d kill out!\n",pdel->data);	//打印出局的猴
		free(pdel);                             //释放删除结点
		pdel = NULL;
		phead = phead->next;	//删除一个节点,下一局从删除结点的后一个位置开始报数
	}
	printf("%d is monkey King\n",phead->data);  //打印最后的猴王
	free(phead);
	return 0;
}

 双向链表

//双向链表的定义
typedef struct node
{
    int data;           //数据域
    struct node* pri    //指针域指向上一结点
    struct node* next;  //指针域指向下一结点
}linklist_t;

顺序表和链表的区别

相同点:两者的逻辑结构都是线性的

不同点:顺序表采用顺序存储,数据在内存连续;

              链表采用链式存储,数据在内存中不连续,通过指针链接到一起;

              顺序表插入和删除麻烦,但查找速度快且可以随访问;

              链表插入和删除方便,但是查找速度慢。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值