1. 程式人生 > >資料結構——從順序表中刪除重複的元素

資料結構——從順序表中刪除重複的元素

問題描述:設計一個演算法從順序表中刪除重複的元素,並使剩餘元素間的相對次序保持不變。
例如:原順序表為{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);

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();
}