数据结构----线性表之链式存储


以下内容只是学习记录:

一、链式存储定义

  用一组任意存储位置存储数据元素,存储位置可以连续也可以不连续,存储格式如下图:

 由结构图可以看出链式存储相比于顺序存储

  优点:

      1、插入删除灵活,只需修改指针即可

      2、内存动态分配,无需像顺序表那样存储空间不够需要额外写代码动态增加存储空间

  缺点: 1、存储密度小,即存储空间利用率低

      2、查找数据没有顺序表方便,顺序表可以通过下标直接计算存储地址,而单链式结构查找数据需要从表头开始一个一个查找

二、链式存储实现

  单链表代码实现:

    1、创建单链表结构体    

#define ElemType int

typedef struct ListNode
{
	ElemType data;//数据域
	struct ListNode *next;//指向下一个节点的指针
}ListNode;
typedef ListNode* List;//给ListNode*重新起个名字 ,关于结构体的定义以及使用,请参考博客:

    2、定义一个单链表并初始化为NULL

void InitList(List *head)
{
	(*head) = NULL;
}

void main()
{
	List mylist ;//List表示类型为ListNode结构体的指针变量
	InitList(&mylist);//这里必须要传入mylist的地址,否则就是拷贝传递,最终返回时,mylist还是没有改变
	printf("%p",mylist);
}

 代码解析:

     3、创建链表并赋值

      (1) 头插法

        下图为头插法示意图,即在头节点和链表之间插入一个节点

         代码如下:

void HeadCreatList(List *head)
{
	for (int i = 1; i < 10; i++)
	{
		ListNode *s = (ListNode *)malloc(sizeof(ListNode));
		assert(s != NULL);
		s->data = i;
		s->next = (*head)->next;
		(*head)->next = s;
	}
	
}

 注:使用头节点的好处:

            1、火车跑得快全靠火车头,链表要安全全靠头节点,可以保护头节点不变

            2、代码实现较简单。不信?你可以自己动手写一个不带头节点的链表实现,对比一下!

            3、可以用头节点数据区存储链表的额外信息,比如链表的长度等,这样计算链表长度直接查询头节点即可获得

      使用头节点的好处:

            占用空间增大,但我认为这点头节点占据的存储空间相比较它带来的好处可忽略

      (2) 尾插法

        下图是尾插法示意图

         代码如下:

void TailCreatList(List *head)
{
	ListNode *p = *head;
	for (int i = 1; i < 10; i++)
	{
		p = p->next = (ListNode *)malloc(sizeof(ListNode));
		assert(p != NULL);
		p->data = i;
		p->next = NULL;
	}
}

      (3)显示链表

void ShowList(List head)
{
	ListNode *p = head->next;//head指向的下一个节点数据才是真正的数据开始
	while (p != NULL)
	{
		printf("%d-->", p->data);
		p = p->next;
	}
	printf("Nul.\n");
}