数据结构——从顺序表中删除重复的元素

问题描述:设计一个算法从顺序表中删除重复的元素,并使剩余元素间的相对次序保持不变。
例如:原顺序表为{4 2 8 4 2 1 2 1 3 5 2},执行该算法后,顺序表为:{4 2 8 1 3 5}。
另外,顺序表的初始值通过调用算法
initRandomize(int *arr, int n, int min, int max)产生。

关于rand(),srand()相关基础知识参考以下内容:
https://blog.csdn.net/chikey/article/details/66970397
一、rand()

rand()函数用来产生随机数,但是,rand()的内部实现是用线性同余法实现的,是伪随机数,由于周期较长,因此在一定范围内可以看成是随机的。

rand()会返回一个范围在0到RAND_MAX(32767)之间的伪随机数(整数)。

在调用rand()函数之前,可以使用srand()函数设置随机数种子,如果没有设置随机数种子,rand()函数在调用时,自动设计随机数种子为1。随机种子相同,每次产生的随机数也会相同。

rand()函数需要的头文件是:<stdlib.h>

rand()函数原型:int rand(void);

使用rand()函数产生1-100以内的随机整数:int number1 = rand() % 100+1;

二、srand()

srand()函数需要的头文件仍然是:<stdlib.h>

srand()函数原型:void srand (usigned int seed);

扫描二维码关注公众号,回复: 4336911 查看本文章

srand()用来设置rand()产生随机数时的随机数种子。参数seed是整数,通常可以利用time(0)或geypid(0)的返回值作为seed。

使用rand()和srand()产生1-100以内的随机整数:

srand(time(0));

int number1 = rand() % 100+1;

三、使用rand()和srand()产生指定范围内的随机整数的方法

“模除+加法”的方法

因为,对于任意数,0<=rand()%(n-m+1)<=n-m

因此,0+m<=rand()%(n-m+1)+m<=n-m+m

因此,如要产生[m,n]范围内的随机数num,可用:

int num=rand()%(n-m+1)+m;

其中的rand()%(n-m+1)+m算是一个公式,记录一下方便以后查阅。

比如产生10~30的随机整数:

srand(time(0));

int a = rand() % (21)+10;


作者:chikey
来源:CSDN
原文:https://blog.csdn.net/chikey/article/details/66970397

以下为随机数生成函数:

#include <time.h>
void initRandomize(int *arr, int n, int min, int max)
{
    int i = 0;
    srand(time(0));  	/*设置种子,并生成伪随机序列*/
    for (i = 0; i < n; ++i) {
        arr[i] = rand()% (max - min + 1) + min;  /*得到从[min, max]之间的随机数*/
        //printf("%d ", arr[i]);
    }
    //printf("\n\n");
}

以下是完整代码
包含了四个自定义删除相同数的函数
基于《数据结构》严蔚敏版

#include <stdio.h> 
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define LIST_INIT_SIZE 100 	
#define LISTINCREMENT  10 	
typedef int ElemType;	
typedef int Status; 

typedef struct 
{
   ElemType     *elem; 								
   int 			length;		  				
   int 			listsize; 		
} SqList;

// 算法2.3  初始化 
Status InitList_Sq(SqList &L) 
{  
  L.elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
  if (!L.elem) exit(OVERFLOW);        // 存储分配失败
  L.length = 0;                  
  L.listsize = LIST_INIT_SIZE;   
  return OK;
}

// 算法2.4  插入 
Status ListInsert_Sq(SqList &L, int i, ElemType e) 
{  
  ElemType *p, *q;
  if (i < 1 || i > L.length+1) 
  {// i的合法值为1≤i≤ListLength_Sq(L)+1
  	return ERROR;  
  }
  
  if (L.length >= L.listsize) {// 当前存储空间已满,增加容量
    ElemType *newbase = (ElemType *)realloc(L.elem,
                  (L.listsize+LISTINCREMENT)*sizeof (ElemType));
    if (!newbase) return ERROR;   								
    L.elem = newbase;             							
    L.listsize += LISTINCREMENT;  							
  } 
  q = &(L.elem[i-1]);   							
  for (p = &(L.elem[L.length-1]); p>=q; --p) 
  	*(p+1) = *p;									                              											
  *q = e;      
  ++L.length;   
  return OK;
} 

//算法2.5 删除 
Status ListDelete_Sq(SqList &L,int i, ElemType &e)
{
	ElemType *p,*q;
	if(i<1||i>L.length)  return ERROR;
	p=L.elem+i-1; //p=&(L.elem[i-1]);
	e=*p;
	q=L.elem+L.length-1;//最后一个元素的位置
	for(++p;p<=q;p++)
		*(p-1)=*p;
	--L.length;
}

//销毁顺序表操作 
Status DestroyList(SqList &L)
{ 
   free(L.elem);
   L.elem=NULL;
   L.length=0;
   L.listsize=0;
   return OK;

}

#include <time.h>
void initRandomize(int *arr, int n, int min, int max)
{
    int i = 0;
    srand(time(0));  			/*设置种子,并生成伪随机序列*/
    for (i = 0; i < n; ++i) {
        arr[i] = rand()% (max - min + 1) + min;  /*得到从[min, max]之间的随机数*/
        //printf("%d ", arr[i]);
    }
    //printf("\n\n");
}

void ListPrint(SqList &L)
{
	for(int i=1; i<= L.length; i++)
		printf("%d ", L.elem[i-1]);
	printf("\n");
} 

int listdelete1(SqList *L)  //用这个方法结果是错的,暂时没找到原因 
{							//原因找到:删除完一个元素后,j++,导致更新到原来删除位置的元素没有判断 
	int *p,*q;				//解决方法:删除完就不要j++了 ,没有进入删除的再j++ 
	int i,j;
	for(i=0;i<L->length;i++)
	{
		for(j=i+1;j<L->length;)
		{
		if(L->elem[i]==L->elem[j])
		{ 		
		     //p=L->elem+j; 
		    p=&(L->elem[j]);  			
			//q=L->elem+L->length-1; 
			q=&L->elem[L->length-1] ; 
			for(++p;p<=q;++p)
			*(p-1)=*p;
			--L->length;
		}
		else j++; 
		}			
	}
	return OK;   
}


int listdelete2(SqList *L)  //相比与listdelete1少用了两个指针 ,思路是一样的 
{
	int i,j;
	for(i=0;i<L->length;i++)
	{
		for(j=i+1;j<L->length;)
		{
		if(L->elem[i]==L->elem[j])
		{
			for(int m=j+1;m<L->length;m++)
			L->elem[m-1]=L->elem[m];
			L->length--; 
		}
		else j++;	
		}			
	}
	return OK;   
}

void listdelete3(SqList *L)//和之前相比,减少了移动,但开辟了新的空间,也变得繁琐了 
{
	int i,j,k=1;
	int a[50]={L->elem[0]};
	for(j=1;j<L->length;j++)
	{
		int flag=1;
		for(i=0;i<k;i++)
		{
			if(a[i]==L->elem[j])
			{
				flag=0;
				break;
			}			 
		}
		if(flag)
		{
			L->elem[k]=L->elem[j];
			a[k++]=L->elem[j];		
		}	
	}
	L->length=k;
}

void ListDelete_same(SqList *l)   //和listdelete3比不用另外分配空间 
{								  //这四个删除算法中的最优解 
    int j=1,i=0,len=1;
    while(j<l->length)
    {
        for(i=0;i<len;++i)//和已经进入的不重复集合的元素进行比较 
        {
            if(l->elem[i]==l->elem[j])
                break;
    	}
        if(i==len)//意味着上面的for循环是正常结束的,所有没重复,可以进入不重复集合 
            l->elem[len++]=l->elem[j++];
        else
            j++;//说明出现重复元素,j++,判断下一个元素 
    }
    l->length=len;//最后不充分数组的长度就是,进入该数组的个数 
}

const int N=200;
int	main()
{
	int A[N];
	SqList	List;	
	InitList_Sq(List);
	
	initRandomize(&A[0],N,1,10); //生成50个1~10的随机数 
	for(int i=1; i<=N; i++)
		ListInsert_Sq(List,i,A[i-1]);
			
	printf("开始时元素序列为:\n");
	ListPrint(List);
	/* 
	
	listdelete1(&List);
    ListPrint(List);

    listdelete2(&List);
    ListPrint(List);
    
    listdelete3(&List);
    ListPrint(List);
    
    */
    ListDelete_same(&List);
	printf("\n删除后的顺序表L为:");    
    ListPrint(List);
	if(DestroyList(List)) 
	printf("\n成功释放顺序表L");
			
    getchar();
}

猜你喜欢

转载自blog.csdn.net/qq_41856733/article/details/83931210