链表的学习-2
一.单链表的学习
单链表:也叫单向链表,只能从一个方向遍历和进行操作。
单链表分为2种,带头结点的和不带头结点的,这里主要说明一下带头结点的单链表。
二.带头结点的单链表
三.单链表的结点结构体
typedef struct LNode { int data;//存放数据 存放的数据类型也可以是字符等等,为了方便先存放int型。 struct LNode* pNext;//指针指向下个结点 }LNode;
结点的结构体名字可以随便定义看个人喜好
四.链表的初始化
单链表的写法各有个的写法,各有个的风格,这也是网上链表的代码都不太一样的原因,其实理解了链表是怎么操作的后,它们都是一样的。
单链表的操作主要围绕的就是头结点,所以第一步是先创建头结点。
第一步:创建头结点。
LNode* Create_List() { LNode* pHead = (LNode *)malloc(sizeof(struct LNode));//为头结点的创建,申请空间 pHead->data = NULL;//置NULL的原因是头结点不用存数据,如果想存有关的信息也可以的。 pHead->pNext = NULL;//将头结点指向的下一个结点的pNext置为空。理由是头结点的下一个结点的pNext地址随机,防止指针"飞"了 return pHead; //返回头结点 }
头结点建立好了,当然是建立与头结点相关相连的结点。
第二步:创建结点
LNode* Create_Node(int data) { LNode* node = (LNode*)malloc(sizeof(LNode));//为下一个结点分配地址空间 node->data = data;//存放数据 node->pNext = NULL;//建立结点后,指向下一个结点的指针置空。 return node; }
将第一步和第二步返回的结点和头结点链接起来,要不插在头结点后面,要不插在末尾,所以分为头插法和尾插法。
第三步:将头结点和结点链接起来
(1)头插法:
void List_InsertByHead(LNode* pHead,int data) { LNode *node = Create_Node(data); node->pNext = pHead->pNext;//将老结点的地址赋予给新结点的下个结点地址 pHead->pNext = node;//将新结点的地址赋予给头结点的下个结点地址 }
第一第二步加上LNode *node = Create_Node(data),创建了一个新的结点的图示差不多如上图所示。为了显示清晰一点,所以我就多加了一个结点old node。
头插法也就是下面这两句代码,node->pNext = pHead->pNext;pHead->pNext = node;这两句代码不可互换位置,不然old node的位置就会丢失掉。
这样用头插法的方法构建链表,输出结果很显然,是倒着的。有点儿像栈存放数据,然后从栈顶打印数据。(比如我向链表里存放1,2,3,4。遍历打印出来是4,3,2,1)
头插法和插入数据元素的方法可以说是一样的,只不过不是从头插,而是从后面的结点后插入数据元素,需要用到一个指针找到需要插入的位置
(2)尾插法
void Insert_byTail(LNode *pHead, int data)//尾插法链接 { LNode *node = create_node(data); LNode *p = pHead; while (p->next!=NULL)//遍历到最后一个元素插在其后面 { p = p->next; } p->next = node; }
尾插法是利用一个p指针遍历到链表的最后一个数据元素(这里是空链表没有数据元素,其实最后一个就是头结点),然后将结点插在最后一个结点后。
尾插法因为一直往尾部链接数据元素,所以输出结果和头插法相反。