【整理】链表特征以及代码实现

来源:互联网 发布:下载软件推荐 编辑:程序博客网 时间:2024/06/05 18:26
1 基本概念
  由地址不连续的节点序列组成,彼此通过指针进行相互连接构成的数据结构,叫做链表

2.链表的分类
  (1) 单向线性链表
   每个节点中除了存储数据元素本身之外,还需要一个指针,用于记录下一下节点的地址,叫做后指针
   ×   其中第一个节点叫做头节点,指向头节点的指针叫做头指针;最后一个节点叫做尾节点,尾节点的后指针是空指针
  (2) 单向循环链表
   与单向线性链表相似,所不同的是最后一个节点的后指针指向头节点的地址,首位相接构成一头结构
  (3) 双向线性链表
   每个节点中除了存储数据元素本身之处,还需要两个指针,一个指针用于指向下一个节点的地址,叫做后指针,另外一个 指针用于指向前一个节点的地址,叫做前指针
   × 其中头节点的前指针和尾节点的后指针都是空指针
  (4) 双向的循环链表
   与双向线性链表相似,所不同的是头节点的前指针指向尾节点,尾节点的后指针指向头节点,从而构成环状结构
  (5) 数组链表
   链表中的每个元素都是一个数组,也就是说由数组构成的链表
  (6) 链表数组
   数组中的每一个元素都是一个链表,也就是说由链表构成的数组
  (7) 二维链表
   链表中的每一个元素都是一个链表的链表,也就是由链表构成的链表

************************************************************************************
单向线性链表的代码实现:
#include <stdio.h>#include <stdlib.h>//定义节点的数据类型typedef struct Node{int data; //数据内容struct Node *next; // 下一个节点的地址}Node;//定义单链表数据类型typedef struct{Node *head; // 头指针int cnt;//记录链表中元素的个数}List;//向链表的头节点位置插入新节点void push_head(List *pl, int data);//遍历链表中的所有元素void travel(List *pl);//实现创建新节点的功能Node *create_node(int data);//计算链表中元素的个数int size(List *pl);//清空链表中所有的节点void clear(List *pl);//向指定的下标位置插入指定的节点,下标从0开始void insert(List *pl, int pos, int data);//实现向链表的尾部插入新节点的操作void push_tail(List *pl, int data);//实现删除指定下标位置的节点操作void del(List *pl, int pos);//实现删除头节点的功能void pop_head(List *pl);//实现删除尾节点的功能void pop_tail(List *pl);//实现判断链表是否为空int empty(List *pl);//实现判断链表是否为满int full(List *pl);//实现获取关节点的元素值int get_head(List *pl);//实现获取尾节点的元素值int get_tail(List *pl);//实现单链表的逆转void reverse(List *pl);int main(void){//创建单链表,并且进行初始化List list;list.head = NULL;list.cnt = 0;//向链表中插入节点,然后进行遍历push_head(&list, 11);travel(&list);// 11 push_head(&list, 22);travel(&list);// 22 11push_head(&list, 33);travel(&list);// 33 22 11printf("链表中元素的个数是:%d\n", list.cnt); // 3printf("链表中元素的个数是:%d\n", size(&list)); // 3printf("***************************\n");insert(&list, -2, 44);travel(&list);// 33 22 11 44insert(&list, 0, 55);travel(&list);  // 55 33 22 11 44insert(&list, 5, 66);travel(&list);// 55 33 22 11 44 66insert(&list, 2, 77);travel(&list);// 55 33 77 22 11 44 66insert(&list, 20, 88);travel(&list);// 55 33 77 22 11 44 66 88printf("链表中元素的个数是:%d\n", size(&list)); // 8push_tail(&list, 99);travel(&list); // 55 33 77 22 11 44 66 88 99printf("链表中元素的个数是:%d\n", size(&list)); // 9printf("***************************\n");del(&list, -2); //失败travel(&list);  // 55 33 77 22 11 44 66 88 99del(&list, 0);travel(&list); // 33 77 22 11 44 66 88 99del(&list, 8); // 失败travel(&list); // 33 77 22 11 44 66 88 99del(&list, 2);travel(&list); // 33 77 11 44 66 88 99del(&list, 6); travel(&list); // 33 77 11 44 66 88printf("链表中元素的个数是:%d\n", size(&list)); // 6printf("***************************\n");travel(&list); // 33 77 11 44 66 88pop_head(&list);travel(&list);// 77 11 44 66 88pop_tail(&list);travel(&list); // 77 11 44 66printf("链表中头节点的元素值是:%d\n", get_head(&list)); // 77printf("链表中尾节点的元素值是:%d\n", get_tail(&list)); // 66printf("%s\n", empty(&list) ? "链表为空" : "链表不为空");printf("%s\n", full(&list) ? "链表为满" : "链表不为满");printf("链表中元素的个数是:%d\n", size(&list)); // 4printf("***************************\n");travel(&list); // 77 11 44 66reverse(&list);travel(&list); // 66 44 11 77printf("***************************\n");clear(&list);travel(&list); // 啥也没有 printf("链表中元素的个数是:%d\n", size(&list)); // 0return 0;}//实现单链表的逆转void reverse(List *pl){//判断链表为空,或者只有一个节点不需要逆转if (size(pl) <= 1){printf("该链表不需要逆转\n");return;}//提供三个指针分别记录前三个节点的地址Node *p1 = pl->head;Node *p2 = p1->next;Node *p3 = p2->next;//将原来的头节点的Next置为Nullp1->next = NULL;while(p3 != NULL){//让第二个节点的next指向第一个节点p2->next = p1;//p1指向p2指向的节点p1 = p2;//p2指向p3指向的节点p2 = p3;//p3指向下一节点p3 = p3->next;}//特殊处理最后两个节点p2->next = p1;//头指针指向新的节点pl->head = p2;}//实现删除头节点的功能void pop_head(List *pl){//调用del函数del(pl, 0);}//实现删除尾节点的功能void pop_tail(List *pl){//调用del函数del(pl, size(pl) - 1);}//实现判断链表是否为空int empty(List *pl){return NULL == pl->head;// !pl->cnt;// return 0 == pl->cnt;}//实现判断链表是否为满int full(List *pl){return 0;}//实现获取头节点的元素值int get_head(List *pl){if (empty(pl)){return -1; //表示错误 }return pl->head->data;}//实现获取尾节点的元素值int get_tail(List *pl){if (empty(pl)){return -1; //表示错误}Node *p = pl->head;while (p->next != NULL){p = p->next;}return p->data;}//实现删除指定下标位置的节点操作void del(List *pl, int pos){//1.判断删除的坐标是否合法以及链表是否为空if (pos <0 || pos >=size(pl)){printf("删除的坐标不合法或节点不存在,删除失败\n");return;}//2.当删除头节点时的处理方式if (0 == pos){Node *p = pl->head;pl->head = pl->head->next;free(p);p = NULL;//节点元素的个数减1pl->cnt--;return;}//3.当删除其它位置节点时的处理方式int i = 0;Node *p = pl->head;for (i =1; i <pos; i++){p = p->next;}//记录要删除的节点地址Node *q = p->next;//让删除节点的前一个节点连接删除节点的后一个节点p->next = p->next->next;//释放要删除节点的空间free(q);q = NULL;//元素的个数减1pl->cnt--;}//实现向链表的尾部插入新节点的操作void push_tail(List *pl, int data){//调用insert函数进行插入insert(pl, size(pl), data);}//向指定的下标位置插入指定的节点,下标从0开始void insert(List *pl, int pos, int data){//1.判断插入元素的下标是否合法if (pos <0 || pos > size(pl)){// printf("插入节点的下标不合法\n");// return;// 当坐标不合法时,默认插入到头节点位置// pos = 0;// 当坐标不合法时,默认插入到链表的尾部pos = size(pl);}//2.创建新节点Node *pn = create_node(data);//3.当把新节点插入到头节点位置时的处if (0 == pos){pn->next = pl->head;pl->head = pn;//元素个数加1pl->cnt++;return;}//4.当把新节点插入到其它位置时的处理Node *p = pl->head;int i = 0;//使用循环控制 当pos>1时多出来的next执行for (i =1; i <pos; i++){p = p->next;}//pos = 1时,需要执行的代码pn->next = p->next;p->next = pn;//节点元素的个数加1pl->cnt++;}//计算链表中元素的个数int size(List *pl){return pl->cnt;}//清空链表中所有的节点void clear(List *pl){while(pl->head != NULL){//保存要删除节点的地址Node *pn = pl->head;//让头指针指向下一个pl->head = pl->head->next;//释放要删除的节点free(pn);pn = NULL;}//链表中节点的个数置为0,头指针置为空指针pl->cnt = 0;// pl->head = NULL;}Node *create_node(int data){Node *pn = (Node *)malloc(sizeof(Node));pn->data = data;pn->next = NULL;//返回创建的新节点地址return pn;}//向链表的头节点位置插入新节点void push_head(List *pl, int data){//1.创建新节点//自定义create_node 创建 新节点// Node *pn = create_node(data);// Node *pn = (Node *)malloc(sizeof(Node));// pn->data = data;// pn->next = NULL;//2.将新节点插入到头节点的位置上//pn->next = pl->head;//pl->head = pn;//3.元素个数加1//pl->cnt++;insert(pl, 0, data);}//遍历链表中的所有元素void travel(List *pl){//指定头指针的替身Node *pn = pl->head;printf("链表中的元素是:");while(pn != NULL){printf("%d ", pn->data);//指向下一个节点pn = pn->next;}printf("\n");}

0 0
原创粉丝点击