链表是包含一些数据的独立数据结构(也成为节点)的集合,每个节点都是通过指针链接在一起的。通常节点是动态分配的。事实上,链表中的节点可以存在于内存中的各个地方。,所以在物理上是不是相邻并无影响。
链表在数据结构中占有很大的作用,它可以根据使用情况分配内存,避免内存的浪费。它的插入,删除,查找都是根据指针的访问来实现,删除或添加一个节点不会改变其他数据的位置和内容,和数组相比,链表具有很强的灵活性和可操作性,但是在使用和实现的时候稍微麻烦,而且比较抽象。
单链表
在单链表中,每个节点都包含指向下一个节点的指针,最后一个节点的指针为NULL,以标志最后一个节点。之所以叫单链表也是因为每个节点只存在一个节点指针而已,所以只能顺序访问下一个节点,俗话就是过了这个村就没这个店了。为了记住单链表的第一个位置,可以定义一个头指针head。
单链表的节点创建如下
- typedef struct Linear_chain_node
- {
- int data;
- struct Linear_chain_node *link;
- } NODE;
创建之后,NODE就是节点的数据类型,它是一个包含一个整形数和一个节点指针的封装数据。
建立单链表的函数算法实现
- NODE *Creat_single_chain(int n)
- {
- NODE *head , *current,*previous;
- int i;
- previous=(NODE*)malloc(sizeof(NODE));
- previous->data = 0;
- previous->link = NULL;
- head = previous ;
- for(i=0;i<n;i++)
- {
- current = (NODE*)malloc(sizeof(NODE));
- scanf("%d",current->data);
- current->link = NULL;
- previous->link = current;
- previous = current;
- }
- return head;
- }
建立单链表中,函数是一个指针函数,指针类型是节点,它最终的返回值是头节点。函数里建立了三个节点指针,分别是头节点指针,当前节点指针和前一个节点指针。先建立头指针,数据为0,指针为NULL。通过传递给该函数的参数n来确定节点的个数。在n个循环内一直建立当前节点,当前节点的数据键盘输入,当前节点指针为空。前一节点的指针指向当前节点,最后把当前指针替换为前一个指针进行下一次循环。
单链表中插入节点算法(在第i个节点之前)
- int Insert(NODE *head , int i , int x)
- {
- NODE *current , *new ;
- int j;
- if(i<=0)
- retuen 0;
- current = head;
- j = 0;
- while((j<i-1) && current != NULL)
- {
- current = current->link;
- j++;
- }
- if(current = NULL)
- return 0;
- new = (NODE*)malloc(sizeof(NODE));
- new->data = x;
- new->link = current->link;
- current->link = new;
- return 1;
- }
函数中,先遍历节点,直到找到需要添加节点的位置,如果遍历到最后一个节点,函数返回,如果跳出遍历循环,说明是插入位置,申请一个新的节点,数据为x,指针指向当前节点指向的后一个节点,当前节点(实际上已经是旧的节点)指向新节点。
单链表中的删除算法
- int Delete(NODE *head , int i)
- {
- NODE *previous , *current ;
- int j=1;
- if(i<1)
- return 0;
- previous = head;
- while((j<i) && previous->link != NULL)
- {
- previous = previous->link;
- j++;
- }
- if(previous->link == NULL)
- return 0;
- current = previous->link;
- previous->link = current->link;
- free(current);
- return 1
- }
函数中,先遍历节点,直到找到需要删除节点的位置,将需要删除的节点前一个节点的指针指向其后一个节点,释放内存。
双向链表
顾名思义,双向链表比单链表的多出了一个节点指针,用来指向前一个节点的数据,这样做的好处不言而喻,避免了寻找前面节点时候发生的不方便之举。在数据结构里后面节点称为后继,前面的节点称为前驱。
下面用C描述一下双向链表的建立
实际上,双向链表仅仅加入的前向指针,前向指针指向的是前一个节点,而前一个指针的后向指针也是指向后一个节点,通过这种方式实现了前后访问。单链表理解了之后,双链表理解起来也很简单,原理是差不多的。
双链表的插入算法
- int Insert(NODE *head , int x , int y)
- {
- NODE *current, *new;
- current = head->flink;
- while((current != head) && (current->data != y))
- current=current->flink;
- if(current == head)
- return 0;
- new = (NODE*)malloc(sizeof(NODE));
- new->data = x;
- new->blink = current;
- new->flink = current->flink;
- (current->flink)->blink = new;
- current->flink->new;
- return 1;
- }
双链表的删除算法
- int Delete(NODE *head,int x)
- {
- NODE *current;
- current = head->flink;
- while((current != head) && (current->data != x))
- current=current->flink;
- if(current == head)
- return 0;
- (current->blink)->flink = current->flink;
- (current->flink)->vlink = current->blink;
- free(current);
- return 1;
- }
- typedef struct double_chain_node
- {
- int data;
- struct double_chain_node *blink,*flink;
- }NODE;
- NODE *Ceate_double_chain(int n)
- {
- int i;
- NODE *head , *previous ,*current;
- previous = (NODE*)malloc(sizeof(NODE));
- previous->data = 0;
- previous->blink = previous->flink = NULL;
- head = previous;
- for(i=0;i<n;i++)
- {
- current = (NODE*)malloc(sizeof(NODE));
- scanf("%d",¤t->data);
- current->flink = NULL;
- current->blink = previous;
- previous->flink = current;
- previous = current;
- }
- return head;
- }