数据结构与算法(C语言)------单向链表1

单向链表

一、定义

将存储数据元素信息的域称为数据域,将存储直接后继位置的域称为指针域。指针域中存储的信息称做指针或链。这两部分信息组成数据元素称为结点。

二、头指针和头节点异同

1、头指针是指向链表第一个结点的指针。注,并不一定是头结点的指针。
无论链表是否为空,头指针均不为空。
2、头结点,为了操作的统一和方便而设立的,放在第一个元素结点之前,其数据域一般无意义。有了头结点,对在第一元素结点前插入和删除第一个结点,其操作与其他结点操作就统一了。

三、代码 (不带头结点的写法)

#ifndef __LINKEDLIST_H
#define __LINKEDLIST_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define OK      1
#define ERROR   0
typedef int states;

/** 结点数据 */
typedef struct {
	int id;
	char name[30];
}ElementType;

/** 线性表的单链表存储结构 */
typedef struct linkedNode{
	ElementType data;            //数据域            
	struct linkedNode *next;     //指针域
}LinkedNode;


/** 线性表的单链表表头结构 */
typedef struct linkedList{
	struct linkedNode *headptr;
	int length;
}LinkedList;


/** 链表初始化 */
states InitLinkedList(LinkedList *ptrl);

/** 向链表中插入结点 (按照位置下标插入)*/
states InsertLinkedList(LinkedList *ptrl, int pos, ElementType data);

/** 从链表中删除结点 */
states DeleteLinkedList(LinkedList *ptrl, int pos, ElementType *data);

/** 单链表的读取 */
states GetLinkedListElem(LinkedList *ptrl, int pos, ElementType *data);

/** 获取链表中结点个数 */
int GetLinkedListLength(LinkedList *ptrl);

/** 链表的整表创建操作 --头插法 */
void CreateLinkedList_H(LinkedList *ptrl);

/** 链表的整表创建操作 --尾插法 */
void CreateLinkedList_T(LinkedList *ptrl);

/** 链表的整表删除操作 */
states ClearLinkedList(LinkedList *ptrl);

/** 链表节点的打印 */
void PrintfLinkedList(LinkedList *ptrl);

#endif  /* __LINKEDLIST_H */

#include "linkedlist.h"

/** 链表初始化 */
states InitLinkedList(LinkedList *ptrl)
{
	ptrl->headptr = NULL;
	ptrl->length = 0;
	return OK;
}

/** 向链表中插入结点 (按照位置下标插入)*/
states InsertLinkedList(LinkedList *ptrl, int pos, ElementType data)
{
	int i;
	LinkedNode * tempNode, *node;
	//判断pos的输入范围是否正确
	if(pos < 1 || pos > ptrl->length + 1) 
		return ERROR;
	//新建链表结点,
	node = (LinkedNode *)malloc(sizeof(LinkedNode));
	node->data = data;
	node->next = NULL;
	//分两种情况讨论:
	if(pos == 1){
		node->next = ptrl->headptr;
		ptrl->headptr = node;
		ptrl->length++;
		return OK;
	}
	//寻找位置为 pos 的结点指针
	tempNode = ptrl->headptr;
	for(i = 1;i < pos - 1;i++){
		tempNode = tempNode->next;
	}
	node->next = tempNode->next;
	tempNode->next = node;
	ptrl->length++;
	return OK;
}

/** 从链表中删除结点 */
states DeleteLinkedList(LinkedList *ptrl, int pos, ElementType *data)
{
	int i;
	LinkedNode *tempnode,*node;
	//判断链表是否为空
	if(ptrl->headptr == NULL || ptrl->length == 0)
		return ERROR;
	//判断pos的输入范围是否正确
	if(pos < 1 || pos > ptrl->length)
		return ERROR;
	if(pos == 1){
		node = ptrl->headptr;
		*data = node->data;
		ptrl->headptr = node->next;
		free(node);
		ptrl->length--;
		return OK;
	}
	tempnode = ptrl->headptr;
	for(i = 1;i < pos - 1;i++){
		tempnode = tempnode->next;
	}

	node = tempnode->next;
	tempnode->next = node->next;  //链接单链表
	*data = node->data;
	free(node);
	ptrl->length--;
	return OK;
}

/** 单链表的读取 */
states GetLinkedListElem(LinkedList *ptrl, int pos, ElementType *data)
{
	int i;
	LinkedNode *tempnode,*node;
	//判断pos的输入范围是否正确
	if(pos < 1 || pos > ptrl->length)
		return ERROR;
	if(pos == 1){
		node = ptrl->headptr;
		*data = node->data;
		ptrl->headptr = node->next;
		return OK;
	}
	tempnode = ptrl->headptr;
	for(i = 1;i < pos - 1;i++){
		tempnode = tempnode->next;
	}
	node = tempnode->next;
	*data = node->data;
	return OK;
}

/** 获取链表中结点个数 */
int GetLinkedListLength(LinkedList *ptrl)
{
	return ptrl->length;
}

/** 链表的整表创建操作 --头插法 */
void CreateLinkedList_H(LinkedList *ptrl)
{
	int id;
	char name[30];
	LinkedNode *node;
	printf("请输入id:");
	scanf("%d",&id);
	if(id == -1)
		return;
	printf("请输入姓名:");
	scanf("%s",name);
	node = (LinkedNode *)malloc(sizeof(LinkedNode));
	node->next = NULL;
	node->data.id = id;
	strcpy(node->data.name,name);
	node->next = ptrl->headptr;
	ptrl->headptr = node;
	ptrl->length++;
	CreateLinkedList_H(ptrl);
}

/** 链表的整表创建操作 --尾插法 */
void CreateLinkedList_T(LinkedList *ptrl)
{
	int id;
	char name[30];
	static LinkedNode *tailNode;
	LinkedNode *node;

	while(1){
		printf("请输入id:");
		scanf("%d",&id);
		if(id == -1)
			break;
		printf("请输入姓名:");
		scanf("%s",name);
		node = (LinkedNode *)malloc(sizeof(LinkedNode));
		node->next = NULL;
		node->data.id = id;
		strcpy(node->data.name,name);
		if(ptrl->length == 0){
			ptrl->headptr = node;
			tailNode = node;
			ptrl->length++;
		}else{
			tailNode->next = node;
			tailNode = node;
			ptrl->length++;
		}
	}
}

/** 链表的整表删除操作 */
states ClearLinkedList(LinkedList *ptrl)
{
	LinkedNode *q,*p;
	p = ptrl->headptr;
	while(p){
		q = p->next;
		free(p);
		p = q;
		ptrl->length--;
	}
	ptrl->headptr = NULL;
	return OK;
}

/** 链表节点的打印 */
void PrintfLinkedList(LinkedList *ptrl)
{
	int i;
	LinkedNode *node = ptrl->headptr;
	for(i = 0;i < ptrl->length;i++){
		printf("[%d %s] ",node->data.id,node->data.name);
		node = node->next;
	}
}

四、编程笔记

  • 向链表中插入结点 (按照位置下标插入)
    states InsertLinkedList(LinkedList *ptrl, int pos, ElementType data);
    1、判断输入的pos位置变量范围是否正确;
    pos的范围为(1 <= pos <= ptrl->length + 1)
    条件语句:if( pos < 1 || pos > ptrl->length + 1)
    2、建立将要插入链表的的结点,将并其数据域赋值。
    3、分两种情况进行讨论:
    pos == 1时,需要改变链表中的头指针。
    pos > 1时,不需要改变链表中的头指针。首先找到pos - 1位置的结点指针,将新建结点的指针域指向 pos-1结点的下个结点地址。再将pos - 1结点的指针域指向新建结点的地址。
    寻找位于pos位置的结点,如下图:
    当指针从结点1到结点2,指针需要移动1次;当指针从结点1到结点3,指针需要移动2次;所以判断循环条件为for(i = 1;i < pos;i++) { node = node->next;

    【结点1】-->【结点2】-->【结点3】-->NULL
        ↑
    【结点1】-->【结点2】-->【结点3】-->NULL
                   ↑
    【结点1】-->【结点2】-->【结点3】-->NULL
                               ↑         
    【结点1】-->【结点2】-->【结点3】-->NULL
                                        ↑
    
  • 从链表中删除结点(按照位置下标删除)
    从链表删除元素与插入元素的操作相类似。关键在于要删除元素的获取。
    1、判断链表是否为空。
    2、判断pos的输入范围是否正确。(1 - ptrl->length)
    3、分两种情况讨论;pos == 1时;pos >= 1时;

  • 创建单链表(头插法)
    1、新建结点。
    2、将新建结点的next指向ptrl->headptr;
    3、然后将ptrl->headptr指向新建结点地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值