串的數據結構表——順序串與鏈式串


  串的結構類似與線性表,只不過串的數據元素是一個字符,即是由零個或多個字符組成的有限序列。

一、串的順序存儲

  串的順序存儲結構也就是順序存儲,即串中的字符被依次的存在一組連續的存儲單元中,可以類比線性表的順序存儲,可以寫出其數據結構如下:

typedef struct st
{
	char *ch;		//串存放的起始地址,串中第i個字符存儲在ch[i-1]中
	int length;		//串的長度
	int strsize;	//分配的存儲空間的大小,如果不足,在通過realloc()分配增加空間
}string;

   假設現在的字符串是“friend”,其結構可以用如圖所示:

  

  現在我們拿到這個數據結構第一步是要初始化一個串,即首先在內存中開辟一段連續的存儲空間(大小可以假先預定MAXSIZE個存儲空間),初始化其長度length為0,同時制定其串的最大容量是MAXSZIE,如下:

//串的初始化操作
string CreateNullString()
{
	string s;
	s.length=0;
	s.ch=(char*)malloc(MAXSIZE *sizeof(char));
	s.strsize=MAXSIZE;
	return s;
}

 初始化完成之后,我們可以類比順序表,對串完成一系列操作,如串拷貝、取子串、串賦值等,

 程序示例如下:

#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100

typedef struct st
{
	char *ch;		//串存放的起始地址,串中第i個字符存儲在ch[i-1]中
	int length;		//串的長度
	int strsize;	//分配的存儲空間的大小,如果不足,在通過realloc()分配增加空間
}string;

//串的初始化操作
string CreateNullString()
{
	string s;
	s.length=0;
	s.ch=(char*)malloc(MAXSIZE *sizeof(char));
	s.strsize=MAXSIZE;
	return s;
}

//判斷空串
int isEmpty(string s)
{
	if(s.length==0)
		return 1;
	else
		return 0;
}

//賦值操作
void StringAssign(string *s1,char s2[])
{
	int i=0;
	while(s2[i]!='\0')	// '\0' 是字符串的結束符,任何字符串之后都會自動加上'\0'
		i++;			//計算s2的長度
	if(i>s1->strsize)
	{
		//所賦值的字符數組超過字符串的默認容量,則增加存儲空間
		s1->ch=(char*)malloc(i*sizeof(char));
		s1->strsize=i;
	}
	s1->length=i;
	for(i=0;i<s1->length;i++)
		s1->ch[i]=s2[i];	//從第一個字符開始逐個字符賦值
}

//串拷貝操作
void StringCopy(string *s1,string s2)
{
	if(s1->strsize<s2.length)
	{
		s1->ch=(char*)realloc(s1->ch,s2.length*sizeof(char));
		s1->strsize=s2.length;
	}
	s1->length=s2.length;
	int i;
	for(i=0;i<s1->length;i++)
		s1->ch[i]=s2.ch[i];
}

//求串的長度
int StringLength(string s)
{
	return s.length;
}

//串的連接操作
void concat(string *s,string s1,string s2)
{
	if(s->strsize<s1.length+s2.length)
	{
		s->ch=(char*)realloc(s->ch,(s1.length+s2.length)*sizeof(char));
		s->strsize=s1.length+s2.length;
	}
	s->length=s1.length+s2.length;		//兩串連接
	int i;
	for(i=0;i<s1.length;i++)			//將s1復制到s中
		s->ch[i]=s1.ch[i];
	for(;i<s->length;i++)
		s->ch[i]=s2.ch[i-s1.length];	//將s2復制到s中去
}

//取子串操作
int substr(string s,int i,int len,string *t)
{
	/*
		i表示從字符串s的第i個位置開始截取(索引從1開始)
		len表示截取字符串的長度
	*/
	if(i<=0 || i>s.length  || len<0 || len>s.length-i+1)	//參數不合法	
		return 0;
	if(t->length<len)	//存儲空間不夠,繼續分配存儲空間
	{
		t->ch=(char*)realloc(t->ch,len*sizeof(char));
		t->strsize=len;
	}
	t->length=len;
	int k;
	for(k=0;k<t->length;k++)
		t->ch[k]=s.ch[i-1+k];
	return 1;
}

//插入操作
int insertString(string *s,int i,string t)
{
	//在字符串s的第i個位置插入字符串t
	if(i<=0 || i>s->length+1)
		return 0;
	if(s->strsize<s->length+t.length)	//空間不足
	{
		s->ch=(char*)realloc(s->ch,(s->length+t.length)*sizeof(char));
		s->strsize=s->length+t.length;
	}
	int k;
	for(k=s->length-1;k>=i-1;k--)	//將s中的后i個字符后移到后面
		s->ch[k+t.length]=s->ch[k];
	s->length=s->length+t.length;
	for(k=0;k<t.length;k++)				//將t的值賦值給s
		s->ch[k+i-1]=t.ch[k];
	return 1;
}

//刪除操作
int deleteString(string *s,int i,int len)
{
	//從s的第i個字符開始刪除len個字符
	if(i<=0 || i>s->length  || len<0 || len>s->length-i+1)	//參數不合法	
		return 0;
	int k;
	for(k=i+len-1;k<s->length;k++)	//從s的i+len-1個位置開始將其后的所有字符前移
		s->ch[k-len]=s->ch[k];
	s->length-=len;
	return 1;
}

//輸出操作
void print(string s)
{
	int i;
	for(i=0;i<s.length;i++)
		printf("%c",s.ch[i]);
	printf("\n");
}

void main()
{
	string s1=CreateNullString();
	string s2=CreateNullString();
	string s3=CreateNullString();
	char ch[MAXSIZE];
	printf("請輸入主串:\n");
	gets(ch);
	StringAssign(&s1,ch);
	printf("主串 s1 為:");
	print(s1);
	StringCopy(&s2,s1);
	printf("拷貝串操作結果如下,結果如下 s2 :");
	print(s2);
	printf("刪除操作(1——s1.length-3 全刪):");
	deleteString(&s2,1,s1.length-3);
	print(s2);
	printf("插入操作,插入到s2的第2個位置上,請輸入插入的字符串:");
	gets(ch);
	StringAssign(&s3,ch);
	insertString(&s2,2,s3);
	print(s2);
	printf("取子串操作(取s1的子串【2-4】):");
	substr(s1,2,3,&s3);
	print(s3);
	printf("串連接操作【將s1與s3合並】:");
	concat(&s1,s1,s2);
	print(s1);
}

  結果如下:

 


 

二、串的鏈式存儲

  串的鏈式存儲結構稱為串的鏈式存儲,即串中的每一個節點包括兩個部分:數據域和指針域,其中數據域用來存放字符,指針域用來存放指向下一個節點的指針。

  由此可得串的鏈式數據結構如下:

typedef struct node
{
	char ch;			//字符域
	struct node *next;  //指針域,存放下一個結點的地址
}node,*linkstr;

 如下所示:

 

 

 其初始化操作主要是開辟頭結點,同時讓它的下一個指針指向為NULL:

//初始化操作
linkstr CreateNullString()
{	
	linkstr s;
	s=(linkstr)malloc(sizeof(node));
	if(s!=NULL)
		s->next=NULL;
	return s;
}

由此,完整的案例如下:

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

//鏈式串

typedef struct node
{
	char ch;			//字符域
	struct node *next;  //指針域,存放下一個結點的地址
}node,*linkstr;


//初始化操作
linkstr CreateNullString()
{	
	linkstr s;
	s=(linkstr)malloc(sizeof(node));
	if(s!=NULL)
		s->next=NULL;
	return s;
}

//判斷空串
int iEmpty(linkstr s)
{
	if(s->next==NULL)
		return 1;
	else
		return 0;
}

//賦值操作
void Stringassign(linkstr s,char t[])
{
	linkstr p,q,r;
	r=s;		//r始終表示的是尾結點(最后一個非空節點,而不是最后一個NULL節點)。
	q=s->next;
	int i;
	for(i=0;t[i]!='\0';i++)
		if(q!=NULL)
		{
			q->ch=t[i];
			r=q;
			q=q->next;
		}
		else
		{
			//(初始化時只給頭結點分配了存儲空間或者其他情況),如果需要繼續添加數據(其他節點沒分配空間)需要繼續分配
			p=(linkstr)malloc(sizeof(node));
			//添加節點
			p->ch=t[i];
			r->next=p;
			r=p;
		}
		r->next=NULL;
		//將s中原來多余的空間釋放掉
		while(q!=NULL)
		{
			p=p->next;
			free(q);
			q=p;
		}
}

//串拷貝操作
void assign(linkstr s,linkstr t)
{
	//將t串的值賦值給s串
	linkstr p,q,r,u;
	p=t->next;
	q=s->next;
	r=s;
	while(p!=NULL)
	{
		//串s原先分配了空間
		if(q!=NULL)
		{
			q->ch=p->ch;
			r=q;
			q=q->next;
		}
		//若串s原先的空間不夠用
		else
		{
			u=(linkstr)malloc(sizeof(node));
			u->ch=p->ch;
			r->next=u;
			r=u;
		}
		
		//p節點后移
		p=p->next;
	}
	
	//同理,若q的長度過長,可以釋放多余的空間
	while(q!=NULL)
	{
		p=p->next;
		free(q);
		q=p;
	}
	r->next=NULL;
}

//求串的長度
int length(linkstr s)
{
	linkstr p;
	int n=0;
	p=s->next;
	while(p!=NULL)
	{
		n++;
		p=p->next;
	}
	return n;
}

//串的連接操作
void contact(linkstr s,linkstr s1,linkstr s2)
{
	linkstr p,q,r,t;
	r=s;
	p=s1->next;
	q=s->next; 
	while(p!=NULL)
	{
		if(q!=NULL)
		{
			q->ch=p->ch;
			q=q->next;
			r=q;
		}
		else
		{
			//串s原來沒有分配存儲空間,需要申請空間
			t=(linkstr)malloc(sizeof(node));
			t->ch=p->ch;
			r->next=t;
			r=t;
		}
		p=p->next;
	}
	p=s2->next;
	while(p!=NULL)
	{
		if(q!=NULL)
		{
			q->ch=p->ch;
			q=q->next;
			r=q;
		}
		else
		{
			//串s原來沒有分配存儲空間,需要申請空間
			t=(linkstr)malloc(sizeof(node));
			t->ch=p->ch;
			r->next=t;
			r=t;
		}
		p=p->next;
	}

	

	//將串s的多余的空間清除掉(這個情況只可能發生在while的if循環中)
	while(q!=NULL)
	{
		p=q->next;
		free(q);
		q=p;
	}
	r->next=NULL;	
	
}

//截取子串
int substr(linkstr s,int i,int len,linkstr t)
{
	linkstr p,q,r,u;
	if(i<=0 || i>length(s) || i+len-1>length(s) )
		return 0;
	//指針指向s的第i-1個位置
	int j,k;
	for(j=0,p=s;j<i;j++)
		p=p->next;
		
	for(k=0,r=t,q=t->next;k<len;k++)
	{
		if(q!=NULL)
		{
			q->ch=p->ch;
			r=q;
			q=q->next;
		}
		else
		{
			u=(linkstr)malloc(sizeof(node));
			u->ch=p->ch;
			r->next=u;
			r=u;
		}
		p=p->next;
	}
	
	while(q!=NULL)
	{	
		p=q->next;
		free(q);
		q=p;
	}
	r->next=NULL;
	return 1;
}


//插入操作
int insert(linkstr s,int i,linkstr t)
{
	linkstr p,q,r;
	if(i<=0 || i>length(s)+1)
		return 0;
	//指向第i-1個位置
	int j;
	for(j=0,p=s;j<i-1;j++)
		p=p->next;
	q=t->next;
	while(q!=NULL)
	{
		r=(linkstr)malloc(sizeof(node));
		r->ch=q->ch;
		r->next=p->next;
		p->next=r;
		q=q->next;
		p=r;

	}
	return 1;
}

//刪除操作
int deleteString(linkstr s,int i,int len){
	linkstr p,q,r;
	if(i<=0 || i>length(s) || i+len-1>length(s) )
		return 0;
	int j;
	for(j=0,p=s;j<i-1;j++)
		p=p->next;
	for(j=0;j<len;j++)
	{
		q=p->next;
		p->next=q->next;
		free(q);
	}
	return 1;

}

//打印輸出
void print(linkstr s)
{
	 linkstr p=s->next;
	 while(p!=NULL)
	 {
		printf("%c",p->ch);
		p=p->next;
	 }
	 printf("\n");
}

void main()
{
	linkstr s1;
	linkstr s2;
	linkstr s3;
	s1=CreateNullString();
	s2=CreateNullString();
	s3=CreateNullString();
	char str[100];
	printf("請輸入字符串:\n");
	gets(str);
	Stringassign(s1,str);
	printf("串s1:");
	print(s1);
	printf("串s1的長度為:%d\n",length(s1));
	assign(s2,s1);
	printf("串s2:");
	print(s2);
	printf("串s2刪除操作(第三個位置的三個字符刪除 :");
	deleteString(s2,3,3);
	print(s2);
	printf("串連接操作(s3=s1+s2 ):");
	contact(s3,s1,s2);
	print(s3);
	printf("插入操作(從s1的第6個位置插入s3):");
	insert(s1,6,s3);
	print(s1);
	printf("測試截取子串的功能s2(截取s3的第四個位置長度為4的字符串:");
	substr(s3,4,4,s2);
	print(s2);
	printf("測試字Contact的清除過多存儲空間的功能:(將兩個較短的字符[兩個s2]合並寫到s1上去:");
	contact(s1,s2,s2);
	print(s1);
}	

  結果如圖:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM