数据结构——单链表的基本操作

什么是链表

链表是一种链式存取得数据结构,它与数组类似,但是单链表堆内存的运用更加方便,可以在中间添加或者删除一个或者多个元素,不需要向数组那样移动大量元素。链表分为很多种,单链表,双向链表,循环链表。

单链表的建立与初始化

单链表就是一种链式存储的结构,链表中的数据是以结点来表示的,相当于是一个个节点相互连接在一起。

结点:分为两个部分,数据域指针域,用结构体的形式来表示。如下:

typedef struct Node    //定义结点结构体
{
    int date;          //数据域 
    struct Node *next; //指针域
}node;                 //结点名

我们这里需要定义一个结构体指针,来指向这些结点的头结点,我们将这个指针称之为头指针。我们可以运用头指针来寻找到整个链表。我们需要用malloc函数来建立一个头结点,并对其进行初始化。我在结构体的那篇博客里详细介绍了这个函数,这里就不做多解释了。

头结点建立初始化如下:

void Init(node *&n)//*&n的意思是直接引用在main函数中定义的n,不用在函数内再定义
{
	n = (node *)malloc(sizeof(node));//定义结构体指针变量,并为其分配一块内存
	n ->next = NULL;//将指针域赋为空,防止发生内存泄漏
}

int main()
{
	node *n ;//定义一个结构体指针变量
	Init(n);//初始化
	system ("pause");
	return 0;
}

增加结点

我们在单链表中一般运用头插法尾插法的方法来增加一个结点,来达到建立一个链表的目的。

头插法

头插法就是一直将新建立的结点插入到当前链表的头结点之后。

void front(node *&head)                  //头插法
{
    node *n;                             //定义另一个指针变量
    int m,i;
    for(i=0;i<5;i++)
    {
	n = (node *)malloc(sizeof(node));//让其指向一块新建的内存
	scanf("%d",&m);                  //输入一个数
	n->date = m;                     //给他的数据域赋值
	n->next = head->next;            //让这个指针指向head所指向的下一个结点
	head -> next = n;                //连接头结点和新建节点 	
    }
}

如下图所示,帮助理解

如上图所示,循环往复,就依次将结点插入到了链表中,由于是头插法,所以输出的结果也是倒叙输出的

尾插法

尾插法就是一直将新建结点插入到链表的表尾处,在开始时链表中的头结点就是为结点。此后每次插入的新节点就又成为链表的尾结点。

代码如下

void tail(node *&head)                    //尾插法
{
    int m,i;
    node *p1,*p2;                         //定义另一个指针变量
    p1 = head;                            //让p1也指向头结点,代替头节点完成下面的程序
	                                  //要确保头指针head不能改变
    for(i=0;i<5;i++)
    {
	p2 = (node *)malloc(sizeof(node));//让p2指向一块新建的内存
	scanf("%d",&m);                   //输入一个数
	p2->date = m;                     //给他的数据域赋值
	p2->next = p1->next;              //让p2指针指向p1所指向的下一个结点
	p1 -> next = p2;                  //连接尾结点和新建节点 	
	p1 = p2;                          //让p1也指向新建节点,此时新建节点就是链表中的尾结点
    }
}

如下图所示,帮助理解 

创立完成后可以运用循环语句让将结点中的数据输出出来,又称为链表的遍历,代码如下

void print(node *&head)             //输出数据
{
    node *n;               
    n = head->next;                  //跳过头结点输出后面的结点
    while(n)                         //直到n指向空就停止
    {
	printf("%d  ",n->date);      //输出结点中的数据
	n = n->next;                 //让n指向下一个结点
    }
    printf("\n");
}

然后再在main函数中调用这些子函数即可

int main()
{
    node *head ;                     //定义头结点
    Init(head);                      //初始化链表
    front(head);                     //头插法
    tail(head);                      //尾插法
    print(head);                     //输出结点中的数据	
    system ("pause");
    return 0;
}

比较头插法与尾插法可知

  1. 头插法较尾插法简单,但是输出的结果与输入的相反。
  2. 尾插法虽然复杂所运用的指针较多,但是输出的结果与输入的一致。

 

删除节点

建立完链表后,我们如果想要删除链表中的某一数据,就相当于是删除这个数据所在的结点。我们建立链表时一般不会为头结点赋值,所以不用考虑头结点的情况。

代码如下

void Delete(node *&head)             
{
    int m; 
    node *n1,*n2;                         //定义两个指针变量
    n1 = n2 = head;                       //让他们同时指向头结点
    printf("\n请输入想要删出的数据\n");
    scanf("%d",&m);
    while(n1->date != m)                  //通过while循环遍历整个链表
    {
	n2=n1;                            //让n2也指向n1所指向的结点
	n1=n1->next;                      //让n1遍历整个链表
	if(n1==NULL)                      //如果找到表尾还没找到就条纯循环
	{
		break;
	}
    }
    if(n1==NULL)                          //如果n1等于空,就说明没找到该数据
    {
	printf("\n没有%d这个数据\n\n",m);
    }
    else
    {
	n2->next = n1->next;              //此时n1在n2的前一个结点处,让n2指向
	                                  //n1所指向的下一个结点,就相当于将n1哪个结点跳过了
	free(n1);                         //然后再释放掉n1所指向的那块内存
	n1=NULL;                          //再让n1指向空,避免其成为悬空指针
    }
}

如下图所示,帮助理解

修改结点数据

先遍历结点,然后找到该数据所在的结点,然后再修改结点的数据。

代码如下

void Alter(node *&head)                   //修改数据
{
    int m,n;
    node *p;                             //定义结点指针
    p = head;                            //让p指向头结点
    printf("\n请输入想要修改的数据\n");
    scanf("%d",&m);
    while(p->date != m)                  //通过while循环找到那个数据
    {
	p=p->next;                       //让p遍历整个链表
	if(p==NULL)                      //如果找到表尾还没找到就条纯循环		
        {
	    break;
	}
    }
    if(p==NULL)                          //如果p等于空,就说明没找到该数据
    {
	printf("\n没有%d这个数据\n\n",m);
    }
    else
    {
	printf("请输入新的数据\n");
	scanf("%d",&n);
	p->date = n;                     //替换该结点的数据
    }
}

 

查找某一个数据

也是通过遍历,找到该数据,再输出出来

代码如下

void Find(node *&head)                   //查找数据
{
    int m,n;
    node *p;                             //定义结点指针
    p = head;                            //让p指向头结点
    printf("\n请输入想要查找的数据\n");
    scanf("%d",&m);
    while(p->date != m)                  //通过while循环找到那个数据
    {
	p=p->next;                       //让p遍历整个链表
	if(p==NULL)                      //如果找到表尾还没找到就条纯循环
	{
		break;
	}
    }
    if(p==NULL)                          //如果p等于空,就说明没找到该数据
    {
	printf("\n没有%d这个数据\n\n",m);
    }
    else
    {
	printf("%d\n",p->date);          //输出该数据
    }
}

至此,我们完成了对单链表的一些基本简单操作。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值