单链表的基本操作及尝试-插入排序

在前两周我接触了一个让人头疼的东西-链表;

链表简单的说就是创建一个结构体,然后将这些每个数据存入到一个结构体里面去,通过指针的方法将这些结构体连接起来,一环扣一环,就成为了链表

官方概念

首先何谓链表? 
链式存储的线性表,简称链表。链表由多个链表元素组成,这些元素称为节点。结点之间通过逻辑连接,形成链式存储结构。存储结点的内存单元,可以是连续的也可以是不连续的。逻辑连接与物理存储次序没有关系。

链表分为两个域: 
值域:用于存放结点的值 
链域:用于存放下一个结点的地址或位置

简单的介绍:

1- 值域结构体里面包含了咱们要放进去的数据,(这里的演示我简单的放一个存储学生姓名的链表)

2- 链区域 结构体里面还包含一个指向下一个数据的指针。这个指针的将指向下一个元素的地址(这里叫节点)

下来咱们先创建一个结构体:

typedef struct xx
{
    char name[15];//
    struct xx *next;
}Node;

next 是指向下一个节点的指针 name就是我们存放名字的地方 每一个结构体都有这两部分组成

typedef:是一个高级数据特性,利用它可以为某一类型自定义名称

eg:

typedef int lengh;
//关键就在于最后一个单词 这里以后lengh就是int类型的代表
eg:
lengh a=int a;

所以我们上面用Node 以后来代替struct xx类型,算是一种方便吧

好接下开我们来看看放入数据的方法- 头插法

#include<stdio.h>
#include<stdlib.h>



void creatlink(Node *head,int n)//头插法
{
    int i;
    Node *p;
    for(i=0; i<n; i++)
    {
        p=(Node*)malloc(sizeof(Node));//这里存在一个强制类型的转换,为我们的输入的数据开辟一个空间,malloc函数在stdlib文件里;
        gets(p->name);
        p->next = head->next;//p所指新结点的指针域next指向head中的开始结点
        head->next=p;//头结点的指针域next指向p结点,使得p成为新的开始结点
        
    }

}

这里有一个head 表头指针,里面部分放任何东西,其实链表的创建可以不要这个表头指针,有表头指针的优势在于以后遍历时可以看到遍历到第几个元素;

注意:

头插法你输入 1 2 3 4 5 6

其实数据是以6 5 4 3 2 1的方式进行存储的,好比我们把没输入进去新的数字插入到值之前数据的前面的意思;

尾插法:

和头插法的不一样就是把输入的新的数据插入到以前数据的后面

:输入 12 3 4 5 6

就是以1 2 3 4 5 6的方式存储的

void createHeadList()
{
    int n;
    Node * head, *tail, *p;//tail是一个尾指针
    //创建头结点
    head = (Node *)malloc(sizeof(node));
    head->next = NULL;//
    while(scanf("%d",&n) == 1)
    {
        p = (Node *)malloc(sizeof(node));
        p->data = n;
        p->next =NULL;//p默认是我们的最后一个数据 所以他的尾部为空
        tail->next = p;这里注意区分和头插法的区别,tail是我们设置的尾指针 用来一直指向链表的末尾
        tail = p;
    }
    return head;
}

接下来的操作是建立在熟悉创建链表的基础上

void printlink(Node *head)//打印链表
{
    Node *p;
    p=head->next;
    while(p!=NULL)//是否到结尾
    {
        puts(p->name);
        p=p->next;
    }
}

int lenlink(Node *head)//求链表的长度
{
    int len;
    Node *p;
    for(len=0,p=head->next;p!=NULL;len++)//先给p赋值首个元素;
        p=p->next;//p指向下一个元素;
    return len;
}


//插入节点
void sertlink(Node *head,Node *p, int i)//q指向第i个节点,指针p指向需要插入的节点,p带来的是新的节点注意以下的注释
{
    Node *q;
    int n=0;
    for(q=head; n<i&&q->next!=NULL; n++)
    {
        q = q->next;
        p->next = q->next;// 链接后面的指针,将插入的节点和之前的进行🔗,q本来的next赋值给新节点p的next,
        q->next = p;//链接前面的指针,新的插入的节点p的手地址是由原节点q的末尾指向,所以完成了所谓的链接;~!
    }
}


//删除节点
void deletelink(Node *head,int i)//这里不用穿入新的节点,和插入一样,q指向删除节点的前一个i-1节点,p指向删除的节点
{
    Node *p,*q;
    int n;
    for(n=0,q=head; n<i-1&&q->next!=NULL;n++)//
    {
        q = q->next;//寻找第i个节点,这里寻找到第i个节点是通过i-1来找到的
        if(i>0 && q->next!=NULL)
        {
            p = q->next;//q是第i-1个节点,所以q的next赋值给p,p就成为了我们要删除的那个节点
            
            q ->next = p->next;//摘除节点,节点交接
            free(p);//删除以后释放原来的内存,致辞我们的单链表的基本操作就完成了🤪
        }
    }
}

大家一定一定要熟悉上面的单链表的基本操作之后再来看下面的

链表的排序-1

插入排序;

不知插入排序的小伙伴可以去我的上一篇博客看看哦🐶

对于一串数据的插入排序大家都会,可是放到了操作难度极高的链表上就让人有些头大了!

不仅仅得时刻注意链表的头指针,还有将数据交换,所以大家得学会一些基本操作,多看几遍就懂了!!!

⚠️注意:

  • 直接插入排序的思想,就是先默认第一个元素是排序好的,在顺序表中,从后面往前依次进行比较,从而进行排序。但是在单链表中,从后面遍历的话,找结点的前驱非常困难。故从头进行遍历。

void sort(Node * &L){
	Node *p,*pre,*q;
	p = head->next->next;		// 先保存下链表的第二个元素,因为下一步要将链表变成只有一个元素的有序表。  
	head->next->next = NULL;	// 将断点之前的表变成只有一个元素的有序表
	// 从新链表的第二个元素开始遍历整个新链表直至表尾 
	while(p != NULL){
		q = p->next;
		pre = head;	// 先用pre来保存新表,(利用头指针head。
		while(pre->next !=NULL && pre->next->data < p->data) // 遍历pre所指向的有序表head,直至找到比p大的节点 
			pre = pre->next; 
		p->next = pre->next;
		pre->next = p;
		p = q;	
	} 
}


这里我只放出来了函数代码;

在说一点就是插入排序的时间复杂度较高,但空间复杂度很低o(1);

这次的代码还是在网上参考了一些不是很成熟

有什么建议和想法大家可以评论区讨论;

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值