单链表操作,队列,栈实现,以及常见字符串库函数经典实现
立即快要找工作了。数据结构和算法,非常多基础的东西久了没用已经非常不熟练了,必须開始重拾了!
,链表最简单。先从链表入手。后面再写系列的链表面试题总结以及其它数据结构,以下的代码參考了殷人昆老师的教材(数据结构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; }