基础链表练习

实现的基本功能:

  •  实现一个字符串链表,每插入一个字符串,链表会对其进行按字典进行排序。
  •  重复插入的字符串自动忽略。
  •  通过索引号可以获取到对应位置上的字符串。
  •  移除一个特定的元素
  •  返回链表中存储的字符串个数

list.h文件

/**
 * 基础链表练习
 * 实现一个字符串链表,每插入一个字符串,链表会对其进行按字典进行排序(不区分大小写,如a在aa前,aa在b前等),
 * 重复插入的字符串自动忽略,
 * 通过索引号可以获取到对应位置上的字符串。
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef PRACTICE_LIST_H_
#define PRACTICE_LIST_H_
#if defined(__cplusplus) & __cplusplus
extern "C" {
#endif
#define ssize_t int	///<定义类型

/**
 * 链表节点数据结构
 */
typedef struct tagLIST_NODE
{

  char *str;
  struct tagLIST_NODE *next;

}stLIST_NODE, *pstLIST_NODE;

/**
 * 链表数据结构
 */
typedef struct tagLIST
{
  /**
   * 向链表插入一条字符串数据。
   *
   * @return 成功插入返回0,重复插入返回0,失败返回-1。
   */
  int
  (*insert)(struct tagLIST *const list, const char *str);

  /**
   * 从链表中移除一条指定的字符串数据。
   *
   * @return 移除成功返回0,否则返回-1。
   */
  int
  (*remove)(struct tagLIST *const list, const char *str);

  /**
   * 返回链表的长度。
   */
  ssize_t 
  (*length)(struct tagLIST *const list);

  /**
   * 按序号查找到该序号上的字符串。
   *
   * @return 若对应需要上有字符串则把字符串拷贝到缓冲长度为stacklen的stack的缓冲中并返回字符串的长度,\n
   *          否则返回-1。
   */
  ssize_t
  (*lookup)(struct tagLIST *const list, int id, char *stack, size_t stacklen);

  /**
   * 按顺序打印链表中的字符串数据。
   *
   * @return 无。
   */
  void
  (*dump)(struct tagLIST *const list);

  struct tagLIST_NODE *next;	///<定义一个next指针,next指针存的是字符串链表的节点数据结构

}stLIST, *pstLIST;

/**
 * 创建链表。
 * 
 * @retval 链表句柄 创建成功。
 * @retval NULL 创建失败。
 */
extern pstLIST
LIST_create();

/**
 * 释放链表。
 * 
 * @param[in] list 链表句柄。
 *
 * @return 无。
 */
extern void
LIST_release(pstLIST list);

#if defined(__cplusplus) & __cplusplus
}
#endif
#endif

list.cpp文件

#include "list.h"

/**
 * 向链表插入一条字符串数据,每插入一个字符串,链表会对其进行按字典进行排序(不区分大小写,如a在aa前,aa在b前等)
 * @param list 要插入节点的链表
 * @param str 插入链表节点的内容
 * @return 成功返回0;重复插入返回0;失败返回-1。
 * 示例:
   list->insert(list, "abc");
 */
static int
list_insert(struct tagLIST *const list, const char *str)
{
	pstLIST_NODE ptemp = NULL;	//定义一个临时节点置为NULL

	if (!str || strlen(str) == 0)	//如果str指针为空或者待插入字符串为空,插入失败
		return -1;

	ptemp = (pstLIST_NODE)calloc(1, sizeof(stLIST_NODE));	//为临时节点分配空间
	if (!ptemp)	//看临时节点分配是否有效
		return -1;
	ptemp->str = strdup(str);	//存储新字符串
	ptemp->next = NULL;
	
	//寻找插入位置
	if(NULL == list->next)//链表为空(即链表只有头结点,没有数据节点),直接插入到链表尾部
	{
		list->next = ptemp;
		return 0;//插入成功
	}

	pstLIST_NODE pcur = list->next;
	if(strcmp(str, pcur->str) == -1)//str比第一个数据节点小
	{
		ptemp->next = pcur;
		list->next = ptemp;
		return 0;//插入成功
	}
	//定义一个前置指针,遍历链表寻找插入位置
	pstLIST_NODE ppre = pcur;
	while (pcur)
	{
		if(strcmp(pcur->str, str) == 0)
		{
			free(ptemp);
			ptemp = NULL;
			return 0;//忽略
		}else if(strcmp(str, pcur->str) == 1){
			ppre = pcur;
			pcur = pcur->next;
		}else if(strcmp(str, pcur->str) == -1){
			ptemp->next = pcur;
			ppre->next = ptemp;
			return 0;//插入成功
		}
	}
	//循环走完还是没有找到插入位置,那么就插入到链表结尾
	ppre->next = ptemp;
    return 0;
}

/**
 * 从链表中移除一条指定的字符串数据。
 * @param list 要删除节点的链表
 * @param str 要删除的内容(因为插入的内容是唯一的,所以删除时要么唯一删除,要么没有找到删除内容)
 * @return 移除成功返回0,否则返回-1。
 * 示例:
   list->remove(list, str);
 */
static int
list_remove(struct tagLIST *const list, const char *str)
{
	if(!str)
		return -1;
	pstLIST_NODE p = list->next;
	if(!p) return -1;
	if(strcmp(p->str, str) == 0)
	{
		list->next = p->next;
		free(p);
		p = NULL;
		return 0;//删除成功
	}
	while (p->next)
	{
		if(strcmp(p->next->str, str) == 0)
		{
			pstLIST_NODE ptmp = p->next;
			p->next = ptmp->next;
			free(ptmp);
			ptmp = NULL;
			return 0;//删除成功
		}else{
			p = p->next;
		}
	}
	return -1;//没找到需要删除的字符串,删除失败
}

/**
 * 返回链表的长度:该长度不包含链表的头结点
 * @param list 要计算长度的链表
 * @return 返回长度。
 * 示例:
   printf("now len is: %d\n", list->length(list));
 */
static ssize_t
list_length(struct tagLIST *const list)
{
	ssize_t len = 0;
	pstLIST_NODE p = list->next;
	if(!p) return len;
	while (p)
	{
		len++;
		p = p->next;
	}
	return len;
}

/**
 * 按序号查找到该序号上的字符串。
 * @param list 要查找的目标链表
 * @param id 要查找的目标序号(序号从0开始,序号0代表第一个数据节点的字符串)
 * @param stack 查找成功后返回的字符串
 * @param stacklen 返回的字符串的长度
 * @return 若对应需要上有字符串则把字符串拷贝到缓冲长度为stacklen的stack的缓冲中并返回字符串的长度,否则返回-1。
 * 示例:
   list->lookup(list, i, text, sizeof(text));
 */
static ssize_t
list_lookup(struct tagLIST *const list, int id, char *stack, size_t stacklen)
{
	int len = list->length(list);
	pstLIST_NODE p = list->next;
	if(id < len)//输入id在长度范围内
	{
		for (int i = 0; i < id; i++)
			p = p->next;
		if(strlen(p->str) < stacklen)
		{
			strcpy(stack, p->str);
			return (ssize_t)strlen(p->str);
		}else return (ssize_t)-1;//给定的接受缓冲区不够
	}else return (ssize_t)-1;
}

/**
 * 按顺序打印链表中的字符串数据。
 * @param list 要打印的目标链表
 * @return 无。
 * 示例:
   list->dump(list);
 */
static void
list_dump(struct tagLIST *const list)
{
	pstLIST_NODE ptemp = NULL;	//定义一个临时节点
	
	//链表非空
	if (list->next)	
	{
		ptemp = list->next;	//临时节点指向第一个节点
		
		//遍历打印所有节点字符串
		while (ptemp)
		{
			printf("%s\n", ptemp->str);
			ptemp = ptemp->next;
		}
	}else{
        printf("链表是空的\n");
	}
}

/**
 * 初始化一条链表,为该链表创建一个头结点:头结点不存储数据,存储的是链表数据结构(链表相关操作函数的函数指针)
 * @param 无传入参数
 * @return 成功返回该链表的头结点,即一个链表句柄;失败返回NULL。
 */
pstLIST
LIST_create()
{
	pstLIST list = (pstLIST)calloc(1, sizeof(stLIST));//改动过,未知是否错误   --lu

	//分配空间失败返回NULL
	if(!list)
		return NULL;

	// 接口
	list->insert = list_insert;
	list->remove = list_remove;
	list->length = list_length;
	list->lookup = list_lookup;
	list->dump = list_dump;

	list->next = NULL;//next指针域置为NULL

	return list;
}

void
LIST_release(pstLIST list)
{
	//判断链表是否空
	if(!list)
		return;

	pstLIST_NODE p = NULL;	//创建一个临时节点指针

    p = list->next;	//临时节点指向第一个数据节点

	//遍历释放每一个节点空间
	while (p)
	{
		list->next = p->next;	//依次删除排头的节点
		free(p);
		p = NULL;
		p = list->next;
	}

	free(list);//释放头结点
	list = NULL;
}

main.cpp文件(主函数,测试)

#include "list.h"

int
main(int argc, char *argv[])
{
	pstLIST list = NULL;

	list = LIST_create();

	if(NULL != list)
	{
		char text[512];

		list->insert(list, "abc");
		list->insert(list, "bac");
		list->insert(list, "ab");
		list->insert(list, "abcd");
		list->insert(list, "abc");
		list->insert(list, "gh");

		int res = list->lookup(list, 1, text, sizeof(text));
		printf("text = %s, lenOfstr = %d\n", text, res);

		list->dump(list);//遍历字符串打印

		printf("链表的长度为:%d\n", list->length(list));

		list->remove(list, "abc");

		printf("链表的长度为:%d\n", list->length(list));

		LIST_release(list);
	}	

	system("pause");
	return 0;
}

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值