ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

带头结点的单链表

2022-06-30 19:00:41  阅读:146  来源: 互联网

标签:node 结点 单链 带头 head next now


带头结点的单链表

  与顺序表相同,链表也是一种线性表。与顺序表不同的是,链表的物理存储结构是用一组地址任意的存储单元存储数据。它不像顺序表那样需要占据一段地址连续存储空间,而是将存储单元分散在内存的任意地址上。

  在链表结构中,每个数据元素都存放在链表中的一个结点(node)上,而每个结点之间通过指针将其连接起来,这样就形成了一条如“链”的结构。

  在C程序中,链表中的每个结点都可以用结构体来表示。在链表的每个结点中都必须有一个存放指针(地址)的域,也叫做指针域,指针域用来保存后继结点的地址,这样就将每个结点连接在一起,形成一条链。

  一个链表中通常有一个表头,表头的用来保存第一个结点的地址。一个链表的最后一个结点的指针域要置空(NULL),因为它没有后继结点。

单链表的特点

  • 除“第一个”数据元素外,其余数据元素有且仅有一个 前驱元素 prev,

  • 除“最后一个”数据元素外,其余数据元素有且仅有一个 后继元素 next

  • 单链表的每个结点只有一个指针域

结点:每一个结点都包含两个部分:数据域指针域。数据域用于存放数据元素,指针域用于存放后继结点的地址。

头指针:无论链表是否为空,头指针均不为空,头指针是链表的必要元素,头指针指向表头结点
头结点:放在第一个元素结点之前,其数据域一般无意义(当然也可以用来存放链表的长度等)
首元结点:第一个元素的结点,它是表头结点之后的第一个结点。

  带头结点的单链表在后期的维护中更方便,头结点与其他结点一样拥有数据域指针域,头结点的数据域可以不存储任何信息,但也可以存储如链表长度等附加信息。 头结点的指针域用于保存首元结点的地址。带头结点的单链表的相关代码如下。


带头结点的单链表操作


单链表元素结点

单链表的结点(LNode)通常使用结构体表示。

typedef struct node
{
    //结点数据域
    int data;
    //结点指针域
    struct node *next;
}LNode;

单链表头结点

单链表的头结点(HNode)也使用结构体表示,头结点的指针域保存首元结点的地址,所以其指针域的类型需要与元素结点类型相同。

typedef struct head
{
    //记录链表长度
    int len;
    LNode *next;
}HNode;

创建带头结点的单链表

创建一个带头结点的单链表,并返回一个指向单链表头结点的头指针。头指针用来标识单链表,保存单链表的入口地址。

/***************************************************************
函数功能: 创建带头结点的单链表
入口参数: 无
返回值: head(单链表头指针)
****************************************************************/
HNode *create_linked_list(void)
{
    //创建一个头指针
    HNode*head = NULL;
    //创建一个头结点,并将头指针指向头结点
    head = (HNode*)malloc(sizeof(HNode));
    head->len = 0;
    head->next = NULL;
    return head;
}

打印单链表

打印单链表的所有元素。

/***************************************************************
函数功能: 打印带头结点的单链表
入口参数: head(单链表头指针))
返回值:  无
****************************************************************/
void print_linked_list(HNode*head)
{
    LNode *list = NULL;
    list = head->next;
    while(list)
    {
        printf("%d ", list->data);
        list = list->next;
    }
    printf("\n");
}

例如:

单链表:1 2 3 4 5 6 7 8 9

输出:1 2 3 4 5 6 7 8 9


尾插法

在单链表最后一个结点之后插入一个新结点,并将新插入的结点的指针域置NULL,单链表最后一个结点没有后继节点。

/***************************************************************
函数功能: 在单链表最后一个结点之后插入一个结点
入口参数: 
        参数1:head(单链表头指针)
        参数2:x(需要保存的元素数据)
返回值: head(单链表头指针)
****************************************************************/
HNode *add_linked_list_last(HNode *head,int x)
{
    LNode *last_node = NULL;
    last_node = head->next;
    //判断是否为最后一个结点
    while(last_node->next)
    {
        last_node=last_node->next;
    }
    //申请开辟一个结点空间
    LNode *new_node = (LNode*)malloc(sizeof(LNode));
    new_node->data = x;
    new_node->next=NULL;
    //将结点插入最后
    last_node->next = new_node;
    last_node = new_node;
    head->len++;//链表长度加1
    return head;
}

例如:

单链表:1 2 3 4 5 6 7 8 9

插入10后:1 2 3 4 5 6 7 8 9 10


头插法

在单链表首元结点之前插入一个新结点,并将头结点的指针指向新结点。

/***************************************************************
函数功能: 在单链表首元结点之前插入一个结点
入口参数: 
        参数1:head(单链表头指针)
        参数2:x(需要保存的元素数据)
返回值: head(单链表头指针)
****************************************************************/
HNode *add_linked_list_first(HNode *head,int x)
{
    LNode *new_node = NULL;
    //申请开辟一个结点空间
    new_node = (LNode*)malloc(sizeof(LNode));
    new_node->data = x;//保存需要插入的元素
    new_node->next = NULL;
    //将新结点插入到第一个结点之前
    new_node->next = head->next;
    head->next = new_node;
    head->len++;
    return head;
}

例如:

单链表:2 4 7 8 9 1

插入11后:11 2 4 7 8 9 1


删除单链表中第N个结点

删除单链表中的第N个结点,需要将第N-1个结点的后继指针指向第N+1个结点,然后将第N个结点的后继指针置NULL,然后再释放第N个结点的空间。

/***************************************************************
函数功能: 删除单链表中的第N个结点
入口参数: 
        参数1:head(单链表头指针)
        参数2:n(第N个结点)
返回值: head(单链表头指针)
****************************************************************/
HNode *delete_theN_node(HNode *head,int n)
{
    //判断n是否大于链表长度
    if (n > head->len || n < 1)
    {
        printf("该结点不存在!\n");
        return 0;
    }
    LNode *now_node = NULL;
    LNode *prev_node = NULL;
    now_node = head->next;
    //删除第一个结点
    if (1 == n)
    {
        head->next = now_node->next;
        now_node->next = NULL;
        free(now_node);
        now_node = NULL;
        head->len--;
    }
    //删除最后一个结点
    else if(head->len == n)
    {
        while(--n)
        {
            prev_node = now_node;
            now_node = now_node->next;
        }
        prev_node->next = NULL;
        free(now_node);
        now_node = NULL;
        head->len--;
    }
    //删除中间某个结点
    else
    {
        while(--n)
        {
            prev_node = now_node;
            now_node = now_node->next;
        }
        prev_node->next = now_node->next;
        now_node->next = NULL;
        free(now_node);
        now_node = NULL;
        head->len--;
    }
    return head;
}

例如:

单链表:2 4 7 8 9 1

删除第2个结点后: 2 7 8 9 1


删除单链表中元素为X的结点

前提:单链表中不包含重复元素。

/***************************************************************
函数功能: 删除单链表中元素为X的结点(单链表中不包含重复元素)
入口参数: 
        参数1:head(单链表头指针)
        参数2:x(删除的元素数据)
返回值: head(单链表头指针)
****************************************************************/
HNode *delete_num(HNode *head,int x)
{
    LNode *now_node = NULL;
    LNode *prev_node = NULL;
    now_node = head->next;

    //判断X是不是第一个结点的元素
    if(x == now_node->data){
        head->next = now_node->next;
        now_node->next = NULL;
        free(now_node);
        now_node = NULL;
        head->len--;
        return head;
    }
    //判断中间
    while(now_node->next)
    {
        if(x == now_node->data){
            prev_node->next = now_node->next;
            now_node->next = NULL;
            free(now_node);
            now_node = NULL;
            head->len--;
            return head;
        }
        else{
            prev_node = now_node;
            now_node = now_node->next;
        }
    }
    //判断最后一个结点的元素是否为X
    if(x == now_node->data){
        prev_node->next = NULL;
        free(now_node);
        now_node = NULL;
        head->len--;
    }
    else{
        printf("链表中无%d这个元素\n",x);
        return 0;
    }
    return head;
}

例如:

单链表:2 4 7 8 9 1

删除元素9后:2 4 7 8 1


删除单链表中连续重复的元素只保留一个

/***************************************************************
函数功能: 删除单链表中的重复元素
入口参数: head(单链表头指针)
返回值: head(单链表头指针)
****************************************************************/
HNode *delete_repetitive_num(HNode*head)
{
    LNode *now_node = NULL;
    LNode *prev_node = NULL;
    now_node = head->next;

    while(now_node->next){
        prev_node = now_node;
        now_node = now_node->next;
        //判断相邻两个元素是否相等
    if(prev_node->data == now_node->data){
            prev_node->next = now_node->next;
            now_node->next = NULL;
            free(now_node);
            now_node = prev_node;
        }
    }
    return head;
}

例如:

单链表:1 1 2 2 3 3 3 5 5

删除后:1 2 3 5


销毁单链表

销毁除头结点之外的结点。

/***************************************************************
函数功能: 销毁除头结点之外的结点
入口参数: head(单链表头指针))
返回值: head(单链表头指针)
****************************************************************/
HNode *destroy_linked_list(HNode *head)
{
    LNode *now_node = NULL;
    //从第一个元素结点开始销毁
    while(head->next){
        now_node = head->next;
        if(now_node->next == NULL){
            head->next = NULL;
            free(now_node);
            now_node = NULL;
            head->len--;
            break;
        }
        head->next = now_node->next;
        now_node->next = NULL;
        free(now_node);
        now_node = NULL;
        head->len--;
    }
    return head;
}

单链表逆置

说明:此逆置不改变结点原来的位置,只交换两个结点存储的数据。

/***************************************************************
函数功能: 逆置单链表(交换元素数据)
入口参数: head(单链表头指针)
返回值: head(单链表头指针)
****************************************************************/
HNode *reverse_linked_list(HNode *head)
{
    int n = head->len;
    int temp;
    int i,j;
    printf("链表长度:%d\n",n);
    LNode *first_node = NULL;
    LNode *temp1_node = NULL;
    LNode *temp2_node = NULL;

    first_node = head->next;
    temp1_node = first_node;
    //如果链表元素个数为奇数则(n-1)%2,反之n%2
    if(n%2 == 0||(n-1)%2==0)
    {        
        //不管是奇数个元素还是偶数个元素,都只需要交换n/2次
        //奇数个元素其最中间那一个元素不需要交换
        for(i=0;i<n/2;i++)
        {
            temp2_node = first_node;
            for(j=0;j<n-i-1;j++)
            {
                temp2_node = temp2_node->next;
            }
            temp = temp1_node->data;
            temp1_node->data = temp2_node->data;
            temp2_node->data = temp;
            //指向第一个结点的指针往后移动一个
            temp1_node = temp1_node->next;
        }
    }
    return head;
}

例如:

单链表:3 2 4 5 10 8 1

逆置后:1 8 10 5 4 2 3


将两个链表归并为一个有序链表

/***************************************************************
函数功能: 将两个链表归并为一个有序链表
入口参数: 
        参数1:head1(单链表头指针)
        参数2:head2(单链表头指针)
返回值: head3(单链表头指针)
****************************************************************/
HNode *combine_linked_list(HNode*head1,HNode*head2)
{
    HNode *head3 = NULL;
    LNode *now_node = NULL;
    LNode *next_node = NULL;
    int flag = 0;
    int temp;
    int n;
    now_node = head1->next;
    //找head1的最后一个结点
    while(now_node->next){
        now_node = now_node->next;
    }
    //连接head1和head2
    now_node->next = head2->next;
    //合并
    head3 = head1;
    head3->len = (head1->len) + (head2->len);
    n = head3->len;

    //冒泡排序
    for(int i=0;i<n-1;i++)
    {
        now_node = head3->next;
        next_node = now_node;
        for(int j=0;j<n-1-i;j++)
        {
            next_node = next_node->next;
            if(now_node->data > next_node->data)
            {
                temp = now_node->data;
                now_node->data = next_node->data;
                next_node->data = temp;
                flag = 1;
            }
            now_node = now_node->next;
        }
        if(flag == 0){
            break;
        }
    }
    return head3;
}

例如:

单链表1:5 4 3 2 1

单链表2:9 6 8 7

归并后:1 2 3 4 5 6 7 8 9


更新第N个结点的数据

/***************************************************************
函数功能: 修改第N个结点的数据
入口参数: 
        参数1:head(单链表头指针)
        参数2:n(第N个结点)
        参数3:更新的数据
返回值: head3(单链表头指针)
****************************************************************/
HNode *change_theN_node(HNode *head,int n,int x)
{
	//判断n是否大于链表长度
	if (n > head->len || n < 1)
	{
		printf("该结点不存在!\n");
		return 0;
	}
	LNode *now_node = NULL;
	now_node = head->next;
	while(--n)
	{
		now_node = now_node->next;
	}
	now_node->data = x;
	return head;
}

例如:

单链表:5 4 3 2 1

更新第2个结点数据为12:5 12 3 2 1


查找值为X的元素

/***************************************************************
函数功能: 查找值为X的元素
入口参数: 
        参数1:head(单链表头指针)
        参数2:x(查找的值)
返回值: 0 表示不存在,1表示存在
****************************************************************/
int find_data_linked_list(HNode *head,int x)
{
	LNode *now_node = NULL;
	now_node = head->next;
	while(now_node){
		if(now_node->data == x){
			return 1;
		}
		now_node = now_node->next;
	}
	return 0;
}

主函数参考

int main(int argc, char const *argv[])
{
	int num;
	int n;
	//创建一个头指针用于标识链表
	HNode *phead = NULL;
	//创建一个带头结点的单链表
	phead = create_linked_list();

	LNode*new_node = NULL;
	LNode*last_node = NULL;

	printf("请向单链表输入数据:");
	do{
		scanf("%d",&num);
		new_node = (LNode*)malloc(sizeof(LNode));
		new_node->data = num;
		new_node->next = NULL;
		if (phead->next == NULL)
		{
			phead->next = new_node;
			last_node = new_node;
			phead->len++;
		}
		else
		{
			last_node->next = new_node;
			last_node = new_node;
			phead->len++;
		}

	}while(getchar() != '\n');
	//打印链表所有元素
	printf("链表长度:%d\n",phead->len);
	printf("链表所有元素:");
	print_linked_list(phead);
    
    //尾插法
    
    //头插法
	
	//删除第N个结点
	
	//查找数据
	
	return 0;
}

注意:该文章仅供学习交流不得转载商用。

标签:node,结点,单链,带头,head,next,now
来源: https://www.cnblogs.com/codecp/p/16428063.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有