数据结构 链表知识点整理
Posted 金舰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构 链表知识点整理相关的知识,希望对你有一定的参考价值。
首先是链表的定义:
typedef struct NODE{ struct NODE *next; int value; }Node,*Linklist;
其中 Linklist为指向Node的指针;
接下来是几个常用的函数:
一.链表的初始化:
int Linklist_init(Linklist *L)
{
*L = (Linklist)malloc(sizeof(Node));
if(!(*L))
{
printf("创建失败");
return FALSE;
}
(*L)->next = NULL;
return TRUE;
}
问:为什么需要使用Linklist *L
答: 在局部函数中进行用指针修改变量值, 如果我们想修改一个int a的值 需要传入int *a; 即指向int的指针;
同理, 我需要给一个Linklist(指向Node的指针)赋值, 就需要修改Linklist的指针。 即二级指针;
实际测试, 当写成Node *L;L = (Node *)malloc(sizeof(Node)); 时不会报错, 但是L->next 并没有被正确赋值。 当试图对链表操作时系统会崩溃;(猜测是内存被分配了 却无法被指向。)
转自CSDN:
如果是使用一级参数传递,首先是main函数中定义一个Node类型的指针,这个指针用list表示,C语言在定义指针的时候也会分配一块内存,一般会占用2个字节或4个字节,现在在大部分的编译器中占用4个字节,这里用4个字节算。在这4个字节的内存中,没有任何值,所以这个指针不指向任何值。然后传递到函数init_linkedlist中,在init_linkedlist函数中,编译器首先为形参list分配一个临时指针内存块,而语句 list = (LinkedList)malloc(sizeof(Node)); 中函数malloc分配一块内存,并向该程序返回一个指向这块内存的指针,这样形参list就有值了,在list所表示的临时内存区域中填入刚刚分配的内存的这块内存的地址,假设为0x10086,这样使用(*list)就可以访问这块内存(0x10086)中的内容了。此时在函数init_linkedlist中list所代表的这块内存中的内容是有值的,
但是现在的list只是占据了一个零时的内存空间,这种改变并不能反映到main函数中,init_linkedlist函数执行完了,临时的list内存块就被回收了,这样刚刚分配的内存块的地址0x10086没有被记录下来。而我们如果要初始化main函数中的链表list的话,就必须记录记录下这块内存空间(0x10086)。
然后来考虑 二级指针的情况:即 *L = (Node *)malloc(sizeof(Node));
函数的参数是一个二级指针,同样,在执行调用这个函数的时候,临时分配一个指针,这个指针占据一个占用4个字节的内存块(函数执行完要回收的),同时这个临时指针L指向主函数main中定义的list指针,这里假设主函数main中的list指针在内存中的地址为0x12306,
其中L是一块临时内存,list是主函数main的中定义的一个指针,此时list代表的内存块还没有初始化。下面执行内存分配的代码
malloc函数分配了一块内存空间,假设地址为0x10010,由于L指向list所代表的内存块,所以*L等价于list,这样将malloc函数分配的内存块赋值给*L就相当于执行语句
这样在函数init_linkedlist中分配的一段内存也就能在main函数中反映出来了,main函数中list代表的内存块的就指向了新分配的内存,链表初始化完成。
简而言之: malloc所开辟的空间 需要通过一个钥匙(指针) 来访问;子函数的指针传递,传进去的时指针,修改的却是指针指向的内容。 同理 我们只有传进去一个指针的指针,才能修改指针的指针指向的内容(即指针)
然而我更喜欢这种写法。(return大法好——Saber是最强的)
Node* Link_init() { Node *Saber; Saber = (Node*)malloc(sizeof(Node)); Saber ->link = NULL; return Saber; }
感觉没那么麻烦。 0.0
二. 清空链表:
int Linklist_clean(Linklist *L) { Linklist p,q; if(!(*L)->next) { return FALSE; } p=(*L)->next; (*L)->next = NULL; while (p) { q =p->next; free(p); p=q; } printf("已经清空\n"); return TRUE; }
三. 销毁链表:
int Linklist_go_die(Linklist *L) { Linklist p; while(*L) { p = *L; (*L) = (*L)->next; free(p); } printf("已经销毁\n"); return TRUE; }
五.查找链表中是否有整数data:
int Linklist_search(Linklist L,int data) { L = L->next; while(L) { if(data == L->data) { return TRUE; } L=L->next; } return FALSE; }
五.在表尾添加一个元素:
int Linklist_insert(Linklist L,int e) { Linklist s; s = (Linklist)malloc(sizeof(Node)); s->data = e; s->next = NULL; while(L->next) { L = L->next; } L->next = s; return TRUE; }
六.删除链表中第i个元素:
void Linklist_free(Linklist L,int Number) { Linklist Aid; if(Number <= 0) { printf("数据异常"); return; } while(L&&Number) { Aid = L; Number--; L = L->next; }
/*
跳出循环有两种可能:
1. 表到尾部而Number依然大于零。
2. 表未到尾部, Number==0 此时Aid刚好为要删除结点的前一个结点
*/ if(Number>0) { printf("异常\n"); return; } else { Aid->next = L->next; free(L); } }
七.去除链表中重复的数据:
void Linklist_filter(Linklist *L) { Linklist Aid; Linklist p = *L; Linklist_init(&Aid); while(p = p->next) { if(FALSE == Linklist_search(Aid,p->data)) { Linklist_insert(Aid,p->data); } } Linklist_clean(L); *L = Aid; }
于是写出一段程序:
创建一个链表,输入一些值, 去除其中重复的值:
#include <stdio.h> #include <stdlib.h> #include "linklist.h" int main() { Linklist L; int next = 0; Linklist_init(&L); printf("输入一组数据,输入-1退出\n"); while(next != -1) { scanf("%d",&next); if(next != -1) { Linklist_insert(L,next); } } print_Linklist(L); Linklist_filter(&L); print_Linklist(L); return 0; }
以上是关于数据结构 链表知识点整理的主要内容,如果未能解决你的问题,请参考以下文章