单链表操作,队列,栈实现,以及常见字符串库函数经典实现

   立即快要找工作了。数据结构和算法,非常多基础的东西久了没用已经非常不熟练了,必须開始重拾了!

,链表最简单。先从链表入手。后面再写系列的链表面试题总结以及其它数据结构,以下的代码參考了殷人昆老师的教材(数据结构c语言描写叙述),程序在自己电脑的vc 6.0上能通过。可能有哪些地方不正确的,或者有更精练的实现还指出来大家一起学习~


/************************************************************************/
/*                 (带头结点)单链表的结构及基本操作                                               

 1.迭代打印链表
 2.尾递归打印链表
 3.初始化链表
 4.清空单链表
 5.计算表的长度
 6.推断链表是否为空
 7.在链表中查找值为x的元素
 8.在链表中查找第i个结点
 9.将新元素x插入在链表第i个位置
 10.删除第i个元素
 11.将L2的链表拷贝到L1
 12.前插法建链
 13.尾插法建立链表*/

/************************************************************************/

#include "stdafx.h"
#include <stdlib.h>

//链表的数据类型
typedef int DataType;

//链表的结构定义
typedef struct node
{
	DataType data;	//数据域
	struct node *pNext;	//指针域
}LinkNode, *pNode;

//检測内存分配错误
void MemFail(pNode p)
{
	if (NULL == p)
	{
		printf("内存分配出错!\n");
		exit(1);
	}
}

//1.迭代打印链表
void PrintList(pNode pHead)
{
	pNode p = pHead->pNext;
	while (p != NULL)
	{
		printf("%d ", p->data);
		p = p->pNext;
	}
	printf("\n");
}

//2.尾递归打印链表
void PrintListRecursive(pNode pHead)
{
	if (pHead->pNext != NULL)
	{
		printf("%d ", pHead->pNext->data);
		PrintListRecursive(pHead->pNext);
	}
}

//3.初始化链表
void Initialize(pNode &pHead)
{
	pHead = new LinkNode();
	MemFail(pHead);

	pHead->pNext = NULL;		//这一步easy忘记,链表最后一个结点指针域一定指向Null
}

//4.清空单链表
void ClearList(pNode pHead)
{
	pNode p = NULL;
	while (pHead->pNext != NULL)
	{
		p = pHead->pNext;
		pHead->pNext = p->pNext;
		delete p;
		p = NULL;
	}
}

//5.计算表的长度
int GetLength(pNode pHead)
{
	int counter = 0;
	pNode p = pHead;
	while (p->pNext != NULL)
	{
		p = p->pNext;
		counter++;
	}

	return counter;
}

//6.推断链表是否为空
bool IsEmpty(pNode pHead)
{
	return (NULL == pHead->pNext);
}

//7.在链表中查找值为x的元素,没找到返回null
pNode FindData(pNode pHead, DataType x)
{
	pNode p = pHead->pNext;

	while (p != NULL && p->data != x)
	{
		p = p->pNext;
	}

	return p;
}

//8.在链表中查找第i个结点,假设i不合法,函数返回null
pNode FindPos(pNode pHead, int i)
{
	if (i < 0)
	{
		return NULL;
	}
	
	int counter = 0;

	pNode p = pHead;
	while (p != NULL && counter < i)
	{
		counter++;
		p = p->pNext;
	}

	return p;
}

//9.将新元素x插入在链表第i个位置,若i不合理则返回false,否则返回true
bool InsertEle(pNode pHead, DataType x, int i)
{	
	pNode p = FindPos(pHead, i-1);
	if (NULL == p)		//i不合法
	{		
		return false;
	}

	//新增结点
	pNode pNew = new LinkNode();
	MemFail(pNew);
	pNew->data = x;

	//连接上新结点
	pNew->pNext = p->pNext;
	p->pNext = pNew;

	return true;
}

//10.删除第i个元素,若i不合理则返回false,删除的元素放到x
bool DeleteEle(pNode pHead, int i, DataType &x)
{
	pNode p = FindPos(pHead, i - 1);
	if (NULL == p && NULL == p->pNext)
	{
		return false;
	}

	//删除结点
	pNode pDel = p->pNext;
	x = pDel->data;
	p->pNext = pDel->pNext;
	delete pDel;
	pDel = NULL;
}

//11.将L2的链表拷贝到L1
void Copy(pNode L1, pNode L2)
{
	if (NULL == L1)
	{
		return;
	}

	pNode p2 = L2->pNext;
	pNode p1 = L1;

	while (p2 != NULL)
	{
		pNode pNew = new LinkNode();
		MemFail(pNew);
		pNew->data = p2->data;
		p1->pNext = pNew;	
		p1 = pNew;

		p2 = p2->pNext;
	}
	p1->pNext = NULL;		//这一步易忘
}

//12.前插法建链 即新的元素总是插在头结点后面作为第一个结点
//前插法的结果是数据的输入顺序与链表的顺序相反
//以下这个函数将数组a的内容用前插法进行键链
void InsertFront(pNode pHead, DataType a[], int n)
{
	if (NULL == pHead)		//无效头结点
	{
		return;
	}

	for (int i=0; i<n; i++)
	{
		//生成新结点
		pNode pNew = new LinkNode();
		MemFail(pNew);
		pNew->data = a[i];

		pNew->pNext = pHead->pNext;
		pHead->pNext = pNew;
	}
}

//13.尾插法建立链表 这个结果和上面的函数是相反的
void insertTail(pNode pHead, DataType a[], int n)
{
	if (NULL == pHead)		//头结点不合法
	{
		return;
	}

	pNode pTail = pHead;
	for (int i=0; i<n; i++)
	{
		//生成新结点
		pNode pNew = new LinkNode();
		MemFail(pNew);
		pNew->data = a[i];

		pTail->pNext = pNew;
		pTail = pNew;		
	}
	pTail->pNext = NULL;		//链表收尾
}


以下是基础的栈,和队列操作,vs2005上通过,尽管结构非常easy,但亲自过手才是硬道理!


typedef int dataType;		//栈数据类型
#define MAX_SIZE 10		//栈的最大容量

//静态栈结构定义
struct StaticStack
{
	dataType elem[MAX_SIZE];		//数据
	int top;		//指向栈顶的指针
};

//栈的初始化
void InitializeStaticStack(StaticStack &S)
{
	memset(S.elem, 0, sizeof(dataType) * MAX_SIZE);
	//top始终指向栈顶
	S.top = -1;
}

//将元素x压栈
bool StaticStackPush(StaticStack &S, dataType x)
{
	//栈满
	if (MAX_SIZE - 1 == S.top)
	{
		return false;
	}

	S.elem[++S.top] = x;

	return true;
}

//出栈
bool StaticStackPop(StaticStack &S, dataType &x)
{
	//栈空
	if (-1 == S.top)
	{
		return false;
	}
	
	x = S.elem[S.top--];

	return true;
}

/*
void PrintStaticStack(StaticStack &S)
{
	for (int i=0; i<=S.top; i++)
	{
		printf("%d ", S.elem[i]);
	}
}*/

#define INIT_SIZE 10		//动态栈的初始大小
#define INCREMENT 10	//每次栈扩充的大小

//动态栈结构定义
struct DynamicStack
{
	dataType *elem;		//数据
	int top;		//栈顶指针
	int maxSize;		//栈的最大容量
};

//初始化动态栈
void InitDynamicStack(DynamicStack &S)
{
	S.elem = (dataType *)calloc(INIT_SIZE, sizeof(dataType));
	if (NULL == S.elem)
	{
		printf("Dynamic stack memory initialization error!");
		exit(1);
	}

	S.maxSize = INIT_SIZE;
	S.top = -1;
}

/*
void PrintStaticStack(DynamicStack &S)
{
	for (int i=0; i<=S.top; i++)
	{
		printf("%d ", S.elem[i]);
	}
}*/

//压栈
void DynamicStackPush(DynamicStack &DS, dataType x)
{
	//栈满,须要扩展
	if (DS.top == DS.maxSize - 1)
	{
		DS.elem = (dataType *)realloc(DS.elem, DS.maxSize + INCREMENT);
		if (NULL == DS.elem)
		{
			printf("Expand dynamic stack error!\n");
			exit(1);
		}
	}

	DS.elem[++DS.top] = x;
	DS.maxSize += INCREMENT;
}

//出栈
bool DynamicStackPop(DynamicStack &DS, dataType &x)
{
	//栈空
	if (-1 == DS.top)
	{
		return false;
	}

	x = DS.elem[DS.top--];

	return true;
}



#define QUEUE_SIZE 10		//队列的大小

//循环队列结构定义
struct Queue
{
	dataType elem[QUEUE_SIZE];		//数据
	int front;		//队首指针
	int rear;		//队尾指针
};

//初始化队列
void InitQueue(Queue &Q)
{
	memset(Q.elem, 0, sizeof(dataType) * QUEUE_SIZE);

	Q.front = 0;
	Q.rear = 0;
}

//入队
bool EnQueue(Queue &Q, dataType x)
{
	//队列满
	if ((Q.rear + 1) % QUEUE_SIZE == Q.front)
	{
		return false;
	}

	Q.elem[Q.rear] = x;
	Q.rear = (Q.rear + 1) % QUEUE_SIZE;

	return true;
}

//出队
bool DeQueue(Queue &Q, dataType &x)
{
	//队列空
	if (Q.front == Q.rear)
	{
		return false;
	}
	
	x = Q.elem[Q.front];
	Q.front = (Q.front + 1) % QUEUE_SIZE;

	return true;

}

//返回队列当前大小
int GetQueueSize(Queue &Q)
{
	//注意别忘记加QUEUE_SIZE
	//当Q.rear - Q.front < 0时。须要加QUEUE_SIZE
	//当Q.rear - Q.front > 0时。假设加了QUEUE_SIZE后。须要对QUEUE_SIZE取模
	return (Q.rear - Q.front + QUEUE_SIZE) % QUEUE_SIZE;
}

/*
void PrintQueue(Queue &Q)
{
	for (int i=Q.front; i!=Q.rear; i=(i+1)%QUEUE_SIZE)
	{
		printf("%d ", Q.elem[i]);
	}
	printf("\n");
}
*/


近期把一些常见的c语言的字符串库函数參照着网上的程序自己实现了一下,也是方便自己复习总结,里面的实现比較经典,以下的函数在我电脑vs2005上都能通过。但未进行严格的測试。

/************************************************************************/
/* 1.strcpy函数实现
   2.strncpy实现
   3.strcat函数实现
   4.strncat函数实现
   5.strdup实现
   6.strchr实现
   7.strrchr函数实现
   8.strpbrk函数
   9.strstr实现
   10.strlen实现
   11.strlen还有一种实现
   12.strcmp函数实现
   13.strcmpy的一种标准实现
   14.strncpy函数实现
   15.memset函数实现*/   
/************************************************************************/


1.strcpy函数实现

//功能说明:将source的字符串拷贝到dest来
//dest所指向的空间必须有足够的内存来容纳source所指向的字符串
char * my_strcpy(char *dest, const char *source)
{
	assert(dest!=NULL && source!=NULL);
	char *r = dest;

	//*(dest++),先返回*dest, 然后dest++
	//(*(dest++) = *(source++)返回最左边表达式的值
	while ((*(dest++)=*(source++)) != '\0');

	return r;
}
/*
1.注意參数的命名上规范,让人easy明确怎么使用函数
2.第二个參数类型是const char *,防止改动源字符串
3.函数返回值是char *。能够实现链式表达式
4.參数合法性检查。以下的函数相同要遵循这些
*/

2.strncpy实现

//将source的前n个字符串拷贝到dest
char * my_strncpy(char *dest, const char *source, int n)
{
	assert(dest!=NULL && source!=NULL);

	char *r = dest;

	//注意n--和后面一堆不能换,否则会多复制一个
	while (n-- && (*(dest++)=*(source++))!='\0');

	return r;

}

3.strcat函数实现

//将source指向的字符串链接在dest后面
char * my_strcat(char *dest, const char *source)
{
	assert(dest!=NULL && source!=NULL);

	char *r = dest;

	while (*(dest) != '\0')
	{
		dest++;
	}

	while ((*(dest++)=*(source++)) != '\0');

	return r;	
}

 4.strncat函数实现

//将source特定数目字符串链接到dest后面
char * my_strncat(char *dest, const char *source, int n)
{
	assert(dest!=NULL && source!=NULL);

	char *r = dest;

	while (*(dest) != '\0')
	{
		dest++;
	}

	while (n-- && (*(dest++)=*(source++))!='\0');

	return r;	
}

5.strdup实现

//该函数将预先配置内存,然后将制定字符串装入内存
char * my_strdup(const char *pStr)
{
	assert(pStr != NULL);

	char *r = (char *)malloc(strlen(pStr)+1);
	if (NULL == r) 
	{
		printf("Memory Failed!\n");
		exit(1);
	}

	return my_strcpy(r, pStr);

}

6.strchr实现

//函数功能在字符串中查找指定的第一个字符,并返回指向该字符的指针
//若未找到,则返回指向'\0'的字符串指针
char * my_strchr(const char *pStr, char ch)
{
	assert(pStr != NULL);
	while (*pStr!='\0' && *pStr!=ch)
	{
		pStr++;
	}
	return (char *)pStr;
}

7.strrchr函数实现

//函数功能:查找一个字符c在还有一个字符串str中末次出现的位置(也就是从str的右側開始查找字符c首次出现的位置)
char * my_strrchr(const char *pStr, char ch)
{
	assert(pStr != NULL);

	const char *r = NULL;

	while (*pStr != '\0')
	{
		if (*pStr == ch)
		{
			r = pStr;
		}
		pStr++;
	}
	return (char *)r;
}

8.strpbrk函数

//函数功能:在两个字符串中寻找首次共同出现的字符,返回该字符在str1中的地址
char *my_strpbrk(const char *str1, const char *str2)
{
	assert(str1!=NULL && str2!=NULL);

	const char *tmp = str2;

	while (*str1 != '\0' )
	{
		tmp = str2;
		while (*tmp != '\0')
		{			
			if (*str1 == *tmp)
			{
				return (char *)str1; 
			}
			tmp++;
		}

		str1++;
	}
	return NULL;
}

9.strstr实现

//若字符串2包括在字符串1里面,返回它在字符串1中的位置,否则返回NULL
char * my_strstr(const char *strDes, const char *str)
{
	assert(strDes!=NULL && str!=NULL);

	const char *tmpDes = NULL;
	const char *tmpStr = NULL;

	while (*strDes != '\0')
	{
		for (tmpDes=strDes, tmpStr=str; 
			*tmpDes==*tmpStr && *tmpStr!='\0';
			tmpDes++, tmpStr++)
		{}		

		if ('\0' == *tmpStr)
		{
			return (char *)strDes;
		}

		strDes++;
	}

	return NULL;
}

10.strlen实现

//该函数返回字符串长度,不包含后面的'\0'
int my_strlen(const char *str)
{
	assert(str != NULL);

	int k = 0;
	while (++k && *(str++)!='\0');

	return k-1;

}

11.strlen还有一种实现

int my_strlen(const char *str)
{
	assert(str != NULL);

	const char *eos = str;		//eos means end of string
	while (*(eos++) != '\0');

	return (int)(eos - str - 1);
}

12.strcmp函数实现

//两个字符串自左向右逐个字符相比(按ASCII值大小相比較),直到出现不同的字符或遇'\0'为止
//s1>s2,返回值大于0,s1<s2返回值小于0,否则等于0
int my_strcmp(const char *str1, const char *str2)
{
	assert(str1!=NULL && str2!=NULL); 
	
	while (*str1!='\0' && *str2!='\0' && *str1==*str2)
	{
		str1++;
		str2++;
	}

	return (*str1 - *str2);
}

13.strcmpy的一种标准实现

int my_strcmp(const char *str1, const char *str2)
{
	assert(str1!=NULL && str2!=NULL); 

	int ret = 0;
	while (!(ret=*(unsigned char *)str1-*(unsigned char *)str2) && *str2!='\0')
	{
		printf("%c - %c = %d\n", *str1, *str2, *str1-*str2);
		str1++;
		str2++;
	}
	if (ret > 0)
	{
		return 1;
	}
	else if (ret < 0)
	{
		return -1;
	}
	else
	{
		return 0;
	}
}

14.strncpy函数实现

//函数比較两个字符串中前n个字符串大小
int my_strncmp(const char *str1, const char *str2, int n)
{
	assert(str1!=NULL && str2!=NULL); 

	if (n <= 0)
	{
		return 0;
	}

	while (--n && *str1!='\0' && *str1==*str2)
	{
		str1++;
		str2++;
	}

	return (*str1 - *str2);
}

15.memset函数实现

//将指定内存区域的前count个字节设定为指定值
void *my_memeset(void *buffer, int c, unsigned int count)
{
	if (count <= 0)
	{
		return buffer;
	}

	assert(buffer != NULL);
	
	char *p = (char *)buffer;
	while (count--)
	{
		*(p++) = (char)c;
	}
	return buffer;

}


posted on 2017-04-24 18:35  ljbguanli  阅读(228)  评论(0编辑  收藏  举报