链表动画图解及简单操作

链表动画理解及简单操作

  • 链表简述及理解
    • 链表简单操作及图解
    • 获取单链表中结点的个数(单链表长度)
    • 单链表的插入(空表、头部)
    • 单链表的删除
    • 两个单链表的链接
    • 将单链表倒置
    • 链表的遍历
    • 这是关于链表的一些基本的操作,作为记录也是复习一遍。因为是刚开始写博客,动画图解过程可能不是很清楚,但是联系代码一起一起看,然后找一张纸画出逻辑图就会更加清楚,强调一点就是,这里的代码用C语言编写,如果要掌握链表的这些基本结构的话,至少需要把C语言中的结构体和指针能够掌握,不然整个代码很难去分析逻辑图。

链表简述及理解

在这里需要强调的是在学习后面内容的同时要把C语言的指针和结构体掌握
链表
特点:
1.一组任意的存储单元存储线性表中的结构
2.这组存储单元可以是连续的,也可以是不连续的
3.每个元素除了存储数据外,还要存储前驱,后继元素的地址
data | address 存储下一个元素或者下一个元素的地址
数据域 | 指针域
单链表:
n个节点按照链式结构存储
每个节点只包含一个指针
例如有三个元素:
头指针pHead指向第一个元素,记录第一个元素的地址 pHead->第一个元素
第一个元素存储第一个数据和指针域指向第二个元素的地址 (第二个元素不必要紧挨着第一个元素)
第二个元素存储第二个数据和指针域指向第三个元素的地址
第三个元素存储第三个数据并且指针域指向空NULL
在链式存储中元素a1分为两个部分:
a1 包括数据部分 通过next指针指向a2的地址
a2 包括数据部分 通过next指针指向a3的地址
a3 包括数据部分 通过next指针NULL (一共三个元素,最后一个元素指向NULL)
最后一个元素中 next 指针域指向NULL

链表简单操作及图解

typedef int DataType;
typedef struct Node {         //typedef的作用是给结构体取一个别名为Node 
	DataType data;            //之后可以直接用Node定义结构体变量指针  不需要加struct
	struct Node* next;
}Node;

上面定义了一个结点,我们在上述概念中提到过,链表由一系列结点构成,每一个结点包括数据和指针,那么以上结构体中我们定义一个结构体表示链表中的一个结点,链表就是通过结构体指针把结点连接起来就形成链表。

//获取指定位置的元素的地址
Node* getptr(Node* head, int pos)    //传头结点   传位置
{
	Node* p = head;               //定义一个指针指向头结点
	if (p = NULL || pos == 0)     //如果指向节点为空指针代表链表为空或者位置为0
	{
		return head;              //指针为空   返回head则就是返回空   如果是位置0  那么位置0的指着那就是head
	}
	//链表为空的时候,返回为空,链表部位空的时候返回位置0的指针就是头指针
	for (int i = 0; p && i < pos; i++)    //检测p是否为空
	{
		p = p->next;               //p的指针指向p所指向的结点的next指针指向的位置
	}
	return p;
}

我们在上述代码中可以看出来,定义函数时返回时的类型为指针,也就是我们查找到指定位置的元素之后返回值定位置的地址。
下面用动画为大家展示获得指定元素位置的过程:
在用图表示中我们我们在指针位置用^表示指向为NULL
下图中,我们假设要获得第三个元素的地址
主函数需要调用

Node* head = NULL;  //最开始赋值为空表示谁都不指向
Node* p = getptr(head,3);//    定义指针接受函数的返回指针

在链表中添加若干个结点(我们在这里添加了四个结点,对应元素分别为10,5,8,3)
这里实现在链表中查找指定位置的元素,所以需要事先添加结点,后面将会有添加结点的方法
图解从for循环开始,第一个if表示如果查找的位置为0,或者头指针没有指向结点,那么就只有一个头结点,这个时候直接返回头节点。
下面表示链表不为空,或者查找的结点位置不是头结点的的情况。


查找指定位置的元素?

获取单链表中结点的个数(单链表长度)

int getSize(Node* head)
{
	int size = 0;
	Node* p = head;
	while (p)
	{
		size++;
		p = p->next;
	}
	return size;
}

主函数调用

getSize(Node *head);                   //传递链表


获得单链表结点个数?

单链表的插入(空表、头部)

bool insert(Node** head, int position, DataType d)//insert(&head, 0, 10); 传递指针
                                                  //给取Node的地址及就是取Node*的指针
	                                              //将0传递给position  将值10传递给DataType
{

	if (position<0 || position>getSize(*head))    //如果位置小于0或者大于结点个数的最大值
	return false;                                 //返回为假
	Node* node = (Node*)malloc(sizeof(Node));     //定义一个结点  分配一个Node大小
	node->data = d;                               //结点中的元素用d赋值给元素的数据域
	node->next = NULL;                            //节点中的元素用NULL赋值给元素的指针域

//在链表第一个结点的前面插入或者在空链表中插入
	if (position == 0)
	{
		node->next = *head;
		*head = node;
		return true;
	}
//在链表的中间和尾部插入结点的情况
	Node* p = getptr(*head, position - 1);
	Node* r = p->next;
	node->next = r;
	p->next = node;
	return true;
}


在链表头部插入?

在链表中间插入?

链表尾部插入元素?

单链表的删除

Bool  erase(Node **head ,int pos)
{

        If(pos<0||pos>getSize(*head))
         {
         Return false;
         }
    Node  * p = *head;
     If(pos == 0)
{
      *head = (*head)->next;
      Free(p);
      P = NULL;
      Return true;
}
P = getSize(*head,position - 1)
Node *q = p->next;
p->next  = q->next;
free(q);
q = NULL;
return true;
}


链表删除头结点?

链表删除中间结点?
单链表尾部删除?

两个单链表的链接

Void Union(Node *a,Node *b)
{
Node *p = a;
While(p->next)
        P=p->next;
p->next = b;
     }

两个链表连接?

将单链表倒置

void reverse(Node** head)   //在完成节点的添加在之后    Head指向了5
{
	Node* p = *head;        //* *存储的是head的二级地址 所以在赋值之后把head的地址赋值给新定义的指针p
	Node* q = p->next;      //把p的next赋值给q   及就是把节点p的指针指向q   所以q指向p的下一个结点
	if (q = NULL)           //如果q为空值  则表示只有一个则表示只有一个结点   那么直接返回
		return;
	Node* r = q->next;      //定义一个指针r   赋值为q的指针  
//	if (p == *head)          //如果p是头指针      开始赋值是已经让指针p指向了head  所以没有必要去判断
		                    //上面一行可以去掉
		p->next = NULL;     //让头指针的p的指针指向空
	while (true)
	{   
		q->next = p;        //把p赋值给q的指针   也就是让p指向q的下一个结点
		if (r = NULL)       //如果r指向为空
		{ 
			*head = q;      //头指针指向q
			break;
		}
		else               //r不指向空
		{
			p = q;         //p指向q
			q = r;         //q指向r
			r = r->next;  //r指向r的下一个结点
		}
	}
}

链表的遍历

链表中的结点都被访问一次且只被访问一次的过程

void print(DataType d)
{
	printf("%d\n", d);
}

void trave(Node *head,void(*fun)(DataType))     //使用函数指针
{
      Node* p = head;
	  while (p)
	  {
		  fun(p->data);
		  p = p->next;

	  }
}

这是关于链表的一些基本的操作,作为记录也是复习一遍。因为是刚开始写博客,动画图解过程可能不是很清楚,但是联系代码一起一起看,然后找一张纸画出逻辑图就会更加清楚,强调一点就是,这里的代码用C语言编写,如果要掌握链表的这些基本结构的话,至少需要把C语言中的结构体和指针能够掌握,不然整个代码很难去分析逻辑图。

你可能感兴趣的:(链表动画图解及简单操作)