很久没有更新,今天就以链表来进行新一轮的操作
简单介绍链表(C)
说直白一点:链表在C中就是自己用结构体实现一个数据类型,然后这些数据类型大量连接在一起构成一个存放数据的结构。与数组不一样的就是,在内存中数组是连续的,链表不是连续,是因为该结构体中有一成员是指针类型,有关于指针问题,以及指针大小,不知道的大家可以点击这里了解。
还需补充知识就是:结构体,malloc动态开辟内存空间
最根本的单元:struct Node
typedef struct Node {
int data;//成员中用来存放数据的
struct Node* pNext;//成员中用来指向下一个单元的指针
}NODE,*PNODE;
一.链表的创建
首先要了解:头指针,头结点,首结点,尾结点等尤其前三者
头指针:就是一个单纯的指针类型数据,指向头结点
头结点:就是第一个结点,但是这个结点是一个傀儡结点,data部分不存放数据,仅仅在其指指针部分存放首结点的地址
首结点:就是第一个存放数据的有效结点
尾结点:最后一个存放有效数据的结点,其指针指向NULL
其实头指针的作用就相当于是一串葡萄的把,可以用这个把来将一串葡萄提起来
创建过程:
1.首先动态开辟一个结构体类型数据,作为头结点
2.为了保持头结点以后顺利返回,就创建一个尾结点一直移动,创建到哪里就到哪里
3.创建新节点并加入的过程如下:
4.最后返回头指针pHead就可以
代码如下:
PNODE create_List() {
PNODE pHead = (PNODE)malloc(sizeof(NODE));
PNODE pTail = pHead;
pTail->pNext = NULL;
int len = 0;
int val = 0;
printf("请输入长度:");
scanf("%d", &len);
for (int i = 0; i < len; i++) {
printf("请输入数值:");
scanf("%d", &val);
PNODE pNew = (PNODE)malloc(sizeof(NODE));
pNew->data = val;
pTail->pNext = pNew;
pNew->pNext = NULL;
pTail = pNew;
}
return pHead;
}
补充:其中的长度,数值等细节自己了解很容易读懂
二.链表的遍历输出
1.遍历前还是要明白,不管干什么都不要动头指针,只需要借助一个新指针代替就可以。
2.新节点 PNODE p = pHead->pNext ;一步一步后移就可以:p=p->pNext;
void traverse_List(PNODE pHead) {
PNODE p = pHead->pNext;
while (p != NULL) {
printf("%d\t", p->data);
p = p->pNext;//实现更新,指针后移
}
printf("\n");
}
三.链表的判空和求长度
1.判空就是:看指针指向的区域是否为NULL
2.长度也很好理解:就是在遍历的过程中加上一个数值积累并且返回,直接看代码就明白了
int is_empty(PNODE pHead) {
PNODE p = pHead->pNext;
if (p == NULL) {
return 1;//返回1就是说明为空
}
else {
return 0;//说明不是空
}
}
int length_List(PNODE pHead) {
PNODE p = pHead->pNext;
int length = 0;
if (is_empty(pHead))//是空,就返回1,就成立,长度就是0
return length;
else {
while (p != NULL) {
length++;//这里就是说前面提到的数值记录
p = p->pNext;//和遍历一样尽进行指针后移
}
}
return length;
}
四.给链表排序
这里选择冒泡排序,其实给链表排序不怎么常见,但是这里介绍是因为想要引入一种思想:同步更新,避开未知
1.冒泡排序就是两个变量之间的更新关系int i和int j之间以及与len长度之间的关系,我们类比数组,只不过是在数组几乎上用的是链表的内容进行比较
注意这两个变量的初始化与更新
代码如下:
void sort_List(PNODE pHead){
int i,j,tmp;
PNODE p = NULL;
PNODE q = NULL;
int len = length_List(pHead);
for(i = 0,p = pHead->pNext; i < len - 1;++i,p = p->pNext){
for(j = i + 1,q = p->pNext; j < len;++j,q = q->pNext ){
if(p->data > q->data){
tmp = p->data;
p->data = q->data;
q->data = tmp;
}
}
}
return;
}
五.链表的插入
1.关于链表的插入,我只是感慨于两行代码,而我仅仅是感觉到了皮毛,只知道这两行解决了所有插入条件的判断,不禁感慨这两行代码的精辟
while (p != NULL && i < pos - 1) {
p = p->pNext;
i++;
}
if (i > pos - 1 || p == NULL) {
return 0;
}
2.插入还需要了解的就是:整个插入过程
代码如下:
int inesert_List(PNODE pHead, int pos, int val) {
int i = 0;
PNODE p = pHead;
while (p != NULL && i < pos - 1) {
p = p->pNext;
i++;
}
if (i > pos - 1 || p == NULL) {
return 0;
}
PNODE pNew = (PNODE)malloc(sizeof(NODE));
pNew->data = val;
PNODE q = p->pNext;
p->pNext = pNew;
pNew->pNext = q;
return 1;
}
六.链表的删除结点
1.更精辟的就是和插入一样,两行代码解决
2.不同的是:
链表删除直接就是将不要的结点去掉就可以
代码如下:
int delete_List(PNODE pHead, int pos) {
int i = 0;
PNODE p = pHead;
while (i < pos - 1 && p->pNext != NULL) {
p = p->pNext;
i++;
}
if (i > pos - 1 || p->pNext == NULL) {
return 0;
}
PNODE q = p->pNext;
p->pNext = p->pNext->pNext;
free(q);
q = NULL;
return 1;
}
总结:
以上就是一个链表的创建以及其他操作,其中关于内存释放以及内存开辟失败的处理细节没有写,希望大家真正在实现过程中不要忘了,欢迎批评指正,别忘了一键三连哦!!!谢谢观看!!!