目录
下面是关于链表的一些知识点:
链表的操作:
创建链表
遍历链表
判断链表是否为空
求链表长度
插入元素
删除元素
排序链表
这篇笔记是根据郝斌老师的上课讲义整理而得:
前面介绍了连续的存储结构:数组,今天来介绍链表,是用来进行离散的存储。首先我们来介绍typedef 的使用:
typedef struct Student
{int sid;char[20] name;int age;}* pST,ST;ST st;
PST ps = &st;
ps->sid =99;
下面是关于链表的一些知识点:
链表的定义:n个节点离散分配,彼此通过指针相连,每个节点只有一个前驱节点,只有一个后续节点, 首节点没有前驱节点,尾节点没有后续节点。
首节点:第一个存放有效数据的节点。
尾节点:最后一个存放有效数据的节点。
头结点:没有存放数据或者链表大小的一个节点,首节点前面的一个节点。其数据类型和首节点一样。主要为了方便对链表的操作。
头指针:指向头节点的指针变量。
尾指针:指向尾节点的指针变量。
数组和链表的比较:
数组连续,操作方便,获取非常快,长度固定。
链表离散,内存利用率小些(存放额外的指针),插入非常快,查找困难一些。长度不定,动态添加容易。
确定一个链表需要的几个参数:
头指针,有了头指针我们就可以推算出其他所有的信息。
一个链表的节点定义为:
typedefine struct Node
{int data;//数据域,可以是非常复杂的数据结构struct Node * pNext;//指针域
}*PNODE,NODE;
链表的分类
单链表:单向的链表,指针域只指向后面或者前面
双链表:每一个节点有两个指针域,分别指向前节点和后节点
循环链表:能通过任何一个节点找到其他所有的节点
非循环链表:不是循环的链表都是非循环链表
链表的操作:
# include <stdio.h>
# include <malloc.h>
# include <stdlib.h>typedef struct Node
{int data; //数据域struct Node * pNext; //指针域
}NODE, *PNODE; //NODE等价于struct Node PNODE等价于struct Node *</st//函数声明
PNODE create_list(void); //创建链表
void traverse_list(PNODE pHead); //遍历链表
bool is_empty(PNODE pHead); //判断链表是否为空
int length_list(PNODE); //求链表长度
bool insert_list(PNODE pHead, int pos, int val); //在pHead所指向链表的第pos个节点的前面插入一个新的结点,该节点的值是val, 并且pos的值是从1开始
bool delete_list(PNODE pHead, int pos, int * pVal); //删除链表第pos个节点,并将删除的结点的值存入pVal所指向的变量中, 并且pos的值是从1开始
void sort_list(PNODE); //对链表进行排序
创建链表
PNODE create_list(void)
{int len; //用来存放有效节点的个数int i;int val; //用来临时存放用户输入的结点的值//分配了一个不存放有效数据的头结点PNODE pHead = (PNODE)malloc(sizeof(NODE));if (NULL == pHead){printf("分配失败, 程序终止!\n");exit(-1);}PNODE pTail = pHead;pTail->pNext = NULL;printf("请输入您需要生成的链表节点的个数: len = ");scanf("%d", &len);for (i=0; i<len; ++i){printf("请输入第%d个节点的值: ", i+1);scanf("%d", &val);PNODE pNew = (PNODE)malloc(sizeof(NODE));if (NULL == pNew){printf("分配失败, 程序终止!\n");exit(-1);}pNew->data = val;pTail->pNext = pNew;pNew->pNext = NULL;pTail = pNew;}return pHead;
}
遍历链表
void traverse_list(PNODE pHead)
{PNODE p = pHead->pNext;while (NULL != p){printf("%d ", p->data);p = p->pNext;}printf("\n");return;
}
判断链表是否为空
bool is_empty(PNODE pHead)
{if (NULL == pHead->pNext)return true;elsereturn false;
}
求链表长度
int length_list(PNODE pHead)
{PNODE p = pHead->pNext;int len = 0;while (NULL != p){++len;p = p->pNext;}return len;
}
插入元素
bool insert_list(PNODE pHead, int pos, int val)
{int i = 0;PNODE p = pHead;while (NULL!=p && i<pos-1){p = p->pNext;++i;}if (i>pos-1 || NULL==p)return false;//如果程序能执行到这一行说明p已经指向了第pos-1个结点,但第pos-1个节点是否存在无所谓//分配新的结点PNODE pNew = (PNODE)malloc(sizeof(NODE));if (NULL == pNew){printf("动态分配内存失败!\n");exit(-1);}pNew->data = val;//将新的结点存入p节点的后面PNODE q = p->pNext;p->pNext = pNew;pNew->pNext = q;return true;
}
删除元素
bool delete_list(PNODE pHead, int pos, int * pVal)
{int i = 0;PNODE p = pHead;while (NULL!=p->pNext && i<pos-1){p = p->pNext;++i;}if (i>pos-1 || NULL==p->pNext)return false;//如果程序能执行到这一行说明p已经指向了第pos-1个结点,并且第pos个节点是存在的PNODE q = p->pNext; //q指向待删除的结点*pVal = q->data; //删除p节点后面的结点p->pNext = p->pNext->pNext;//释放q所指向的节点所占的内存free(q);q = NULL;return true;}
排序链表
void sort_list(PNODE pHead)
{int i, j, t;int len = length_list(pHead);PNODE p, q;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) //类似于数组中的: a[i] > a[j]{t = p->data;//类似于数组中的: t = a[i];p->data = q->data; //类似于数组中的: a[i] = a[j];q->data = t; //类似于数组中的: a[j] = t;}}}return;
}